見出し画像

Notes C API探訪: データベースにNSFSearch関数検索をかけた時の情報

前回までの記事でディレクトリを展開する仕組みを作ってきました。今回はこれをデータベース内の文書に適用してみたいと思います。
とは言っても、仕組みはほぼディレクトリと同じなので、コードと差分を、要点を絞って説明します。

まずはヘッダーファイルです。

// filepage/database.h

class DatabaseExpander : public FilePage::Expander
{
 QStringList headers_;
public:
 DatabaseExpander();
 virtual void setHeader(QStandardItemModel *pModel) override;
 virtual void operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) override;
};

// 検索イテレータクラス
class NoteIterator : public nxpp::Search::Iterator
{
 FilePage *pPage_; ///< ファイルページへのポインタ
 QStringList *pHeaders_; ///< ヘッダー名リストへのポンタ

public:
 /**
  * @brief コンストラクタ
  * @param pPage ファイルページへのポインタ
  * @param pHeaders ヘッダー名リストへのポンタ
  */
 NoteIterator(FilePage *pPage, QStringList *pHeaders)
   : pPage_(pPage)
   , pHeaders_(pHeaders)
 {}

 /**
  * @brief 関数オブジェクト
  * @param match SEARCH_MATCH構造体
  * @param pItemTable サマリーバッファへのポインタ
  * @return STATUS値
  */
 virtual STATUS operator ()(
     const SEARCH_MATCH &match,
     ITEM_TABLE *pItemTable
     ) override;
};

ディレクトリ版とはクラスの名前が違うだけで、定義内容はまるっきり同じです。

続いて、ソースファイルです。

// filepage/database.cpp

DatabaseExpander::DatabaseExpander()
 : headers_()
{
 headers_
     << FIELD_FORM
     << FIELD_UPDATED_BY;
}

void DatabaseExpander::setHeader(QStandardItemModel *pModel) {
 pModel->setHorizontalHeaderLabels(headers_);
}

void DatabaseExpander::operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) {
 try {
   // 検索コールバック用イテレータを作成
   NoteIterator iterator(pPage, &headers_);

   // ファイル検索を実行
   nxpp::Search()(
         dbPtr->handle(),
         NULLHANDLE,
         "",
         SEARCH_SUMMARY,
         NOTE_CLASS_DOCUMENT,
         &iterator
         );
 }
 // Notesステータスがスローされたらそのエラーメッセージに変換して表示
 catch (nxpp::Status &status) {
   emit pPage->consoleLog(nxpp::qt::fromStatus(status.error()));
 }
 // それ以外の例外ならそのメッセージを表示
 catch (std::exception &ex) {
   std::string what(ex.what());
   emit pPage->consoleLog(QString::fromStdString(what));
 }
}

STATUS NoteIterator::operator ()(
   const SEARCH_MATCH &match,
   ITEM_TABLE *pTable
   ) {
 // 検索がマッチしていて、かつITEM_TABLE構造体ポインタがヌルでない時
 if (match.SERetFlags & SE_FMATCH && pTable) {

   // 列リストの準備
   QList<QStandardItem*> cols;

   // サマリーバッファを名前付きサマリーバッファクラスでラップ
   nxpp::NamedItemTable itemTable(pTable);

   // 名前リストを巡回
   for (auto header : *pHeaders_) {

     // ヘッダー文字列をLmbcsに変換
     auto name = toLmbcsQ(header);

     // 値をVariantとして取得
     auto value = itemTable.value(name);

     // 列リストに追加する箱を用意
     QString data;

     // 指定の名前がサマリーバッファになければその旨を表示
     if (value.type() == 0) {
       data = "(no data)";
     }

     // それ以外の場合
     else {

       // Variant値の文字列化を試みる
       auto resultOpt = value.toString();

       // 文字列化に失敗したらデータタイププレフィックスを、成功ならその文字列を格納
       data = !resultOpt
           ? QString("(Unformattable type: %1").arg(value.type())
           : fromLmbcsQ(resultOpt.value());
     }

     // 列のデータをリストに追加
     cols << new QStandardItem(data);
   }

   // サブモデルに列データを追加する
   pPage_->addRowToSubModel(cols);

 }
 return NOERROR;
}

まず、横軸となるフィールド情報は、今回はFormフィールドと$UpdatedByフィールドのみを定義しています。ディレクトリ版と違い、データベースによって文書内に存在するフィールド情報は千差万別なので、フォーム名と、更新者を自動で記録していく$UpdatedByのみを定義しています。
続いてDatabaseExpander::operator ()メソッドです。この中では、nxpp::Search関数オブジェクトにかける検索フラグから、「SEARCH_FILETYPE」が抜かれています。これにより、検索対象がディレクトリ内のファイル/サブディレクトリから、データベース内の文書に変わります。また、文書と言っても設計文書も同じ文書の仲間なので、続く文書クラスマスクにより、データ文書(設計文書以外の文書)のみに絞っています。
最後にNoteIterator::operator ()メソッドですが、ディレクトリ版と唯一違うのが、DB情報のような特殊なフィールドに対する処理がないところで、それ以外はFileIterator::operator ()と変わりません。

実行例

前述までのコード追加した内容を確認してみます。

スクリーンショット 2021-10-27 8.16.18

フィールドの種類がFormと$UpdatedByだけなので味気ないですが、このような形でデータベース内の文書も展開することができました。

この記事が気に入ったらサポートをしてみませんか?