見出し画像

Notes C API探訪: nxpp::Searchのファイル検索適用例

前回の記事で紹介したnxpp::Search関数オブジェクトクラスの使用例を紹介します。

ディレクトリページ画面

これまで作成してきた、Qt UIアプリケーションのFilePage(コードの記事はこちら、実行例の動画はこちら)に、ディレクトリ中にあるDBファイル、ディレクトリを展開する機能を追加した時の画面がこちらです。

スクリーンショット 2021-10-22 8.02.52

これまでのFilePageに「Expand」ボタンが追加され、このボタンをクリックすると、画面が縦にスプリットし、その右側に、このディレクトリの中の情報が展開されます。この情報を取得しているのが、nxpp::Searchになります。

イテレータサブクラス

まずはイテレータ(nxpp::Search::Iterator)を継承して、FilePageのディレクトリ展開用にカスタマイズします。

ヘッダー定義がこちらです。

// filepage/directorypage.h

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

public:
 /**
  * @brief コンストラクタ
  * @param pPage ファイルページへのポインタ
  * @param pHeaders ヘッダー名リストへのポンタ
  */
 FileIterator(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と、ヘッダーリストへのポインタを格納していることがわかります。

ソースコードはこちらです。

// filepage/directorypage.cpp

STATUS FileIterator::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)";
     }

     // DB情報ならDbInfoで各パートに分解して格納
     else if (name == DBDIR_INFO_ITEM) {
       nxpp::DbInfo dbInfo(value.value());
       QStringList list;
       list << fromLmbcsQ(dbInfo.extract(INFOPARSE_TITLE));
       list << fromLmbcsQ(dbInfo.extract(INFOPARSE_CATEGORIES));
       list << fromLmbcsQ(dbInfo.extract(INFOPARSE_CLASS));
       list << fromLmbcsQ(dbInfo.extract(INFOPARSE_DESIGN_CLASS));
       data = list.join(";");
     }

     // それ以外の場合
     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;
}

NSFSearch関数のコールバックによって呼び出されます。SEARCH_MATCH構造体とITEM_TABLE構造体ポインタによって状況を把握し、ITEM_TABLE構造体からDBファイルやサブディレクトリの情報を取得し、テーブルの行データを作成してFilePage右ペインにあるテーブルに追加する処理をします。名前付きサマリーバッファのデータは、データタイププレフィックスを含んだバイナリーデータです。nxpp::Variantクラスの機能を使って、データタイププレフィックスに応じた文字列に変換しています。

DirectoryExpanderクラス

DirectoryExpanderクラスは、ディレクトリタイプのFilePageでディレクトリ展開機能を提供する関数オブジェクトです。

ヘッダー定義がこちらです。

// filepage/directorypage.h

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

ソースコードがこちらです。

// filepage/directorypage.cpp

DirectoryExpander::DirectoryExpander()
 : headers_()
{
 headers_
 << DBDIR_PATH_ITEM
 << DBDIR_TYPE_ITEM
 << DBDIR_INFO_ITEM
 << DBDIR_LENGTH_ITEM
 << FIELD_TITLE
 << DBDIR_MODIFIED_ITEM
 << DBDIR_PHYSICALPATH_ITEM
 << DBDIR_LINK_ITEM
 << DBDIR_PROPERTIES_ITEM
 << DBDIR_DBOPTIONS_ITEM
 << DBDIR_DBVERSIONS_ITEM
 << DBDIR_DBCREATED_ITEM
 << DBDIR_LASTFIXUP_ITEM
 << DBDIR_QUOTALIMIT_ITEM
 << DBDIR_QUOTAWARNING_ITEM
 << DBDIR_MAXDBSIZE_ITEM
 << DBDIR_ISLOGGED_ITEM
 << DBDIR_LENGTH2_ITEM
 << DBDIR_DBOPTIONS2_ITEM
 << DBDIR_DBOPTIONS3_ITEM
 << DBDIR_DBOPTIONS4_ITEM
 << DBDIR_DATAMODIFIED_ITEM
 << DBDIR_NONDATAMODIFIED_ITEM
 << DBDIR_CURRENTUSAGE_ITEM
 << DBDIR_DAOSSTATE_ITEM
 << DBDIR_DAOSOBJCOUNT_ITEM
 << DBDIR_DAOSSTOREDBYTES_ITEM
 << DBDIR_DAOSSYNCPOINT_ITEM
 << DBDIR_STORAGEPATH_ITEM
 << DBDIR_REPLFLAGS_ITEM
 << DBDIR_DB2_DATABASE_LINK
 << DBDIR_LASTCOMPACT_ITEM
 << "$NIFNSFSIZE" // <= ヘッダー未登録
 << "$NIFNSFSTATE"; // <= ヘッダー未登録
}

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

void DirectoryExpander::operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) {
 try {
   // 検索コールバック用イテレータを作成
   FileIterator iterator(pPage, &headers_);
   
   // ファイル検索を実行
   nxpp::Search()(
         dbPtr->handle(),
         NULLHANDLE,
         "",
         SEARCH_FILETYPE | SEARCH_SUMMARY,
         FILE_DBANY | FILE_DIRS,
         &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));
 }
}

DirectoryExpanderの継承元、Expanderクラスについては後日紹介します。

まとめ

nxpp::Searchクラスの使用例をご紹介しました。今回はディレクトリ検索として使いましたが、次回以降でデータベース内の文書(データ文書、設計文書ともに)を検索する使用例もご紹介する予定です。

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