Notes C API探訪: nxpp::Searchのファイル検索適用例
前回の記事で紹介したnxpp::Search関数オブジェクトクラスの使用例を紹介します。
ディレクトリページ画面
これまで作成してきた、Qt UIアプリケーションのFilePage(コードの記事はこちら、実行例の動画はこちら)に、ディレクトリ中にあるDBファイル、ディレクトリを展開する機能を追加した時の画面がこちらです。
これまでの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クラスの使用例をご紹介しました。今回はディレクトリ検索として使いましたが、次回以降でデータベース内の文書(データ文書、設計文書ともに)を検索する使用例もご紹介する予定です。