![見出し画像](https://assets.st-note.com/production/uploads/images/62616734/rectangle_large_type_2_c84de5a5d95afa1cb9097adbabce98ec.png?width=1200)
Notes C API探訪: データベース/ディレクトリ情報をUIに反映する
前回の記事で、FilePageクラスを定義しました。FilePageクラスは、TabPageクラスを継承したタブページの派生クラスで、中身としては、ブックマークと呼んでいる「パス名」と「サーバー名」で構成されたデータを元に、データベース/ディレクトリを開いて、取得できる情報を表に出力する機能を持ちます。
「データベース/ディレクトリを開く」という機能は、Notes C APIのNSFDbOpen関数やNSFDbOpenExtended関数などを使うわけですが、これらは「データベースを開く」だけでなく「ディレクトリを開く」こともできることが、ある意味特殊です。そのため、先のFilePageクラスは、「DatabasePage」としなかったのです。データベースかディレクトリかは、開いた後でNSFDbModeGet関数を使って判定をします。
さて、FilePageクラスで表を出力するために情報をロードしますが、データベースとディレクトリには情報そのものが違います。ディレクトリはパス情報くらいですが、データベースには、パス情報に加え、タイトルやデータベースID、割当情報などいろんなものがあります。
そこで、判定によってデータベースか、ディレクトリかがわかったら、それぞれに特化したデータのロードプロセスが必要になります。そこでローダー関数オブジェクトの出番です。
まずはディレクトリ用のローダー関数オブジェクトを見てみます。
// filepage/directorypage.h
#ifndef DIRECTORYPAGE_H
#define DIRECTORYPAGE_H
#include "../filepage.h"
class DirectoryLoader : public FilePage::Loader
{
public:
virtual void operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) override;
};
#endif // DIRECTORYPAGE_H
続けてソースファイルです。
// filepage/directorypage.cpp
#include "directorypage.h"
void DirectoryLoader::operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) {
addPaths(pPage, dbPtr);
}
ディレクトリについては、パスの情報のみ表示しています。継承元のFilePage::Loaderが持っているaddPathsメソッドで、パス情報を表に書き出しています。
次はデータベース用のローダー関数オブジェクトを見てみます。
// filepage/databasepage.h
#ifndef DATABASEPAGE_H
#define DATABASEPAGE_H
#include "../filepage.h"
class DatabaseLoader : public FilePage::Loader
{
public:
virtual void operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) override;
private:
/**
* @brief データベース情報の書き込み
*/
void addDbInfo(FilePage *pPage, nxpp::DbPtr dbPtr);
/**
* @brief DBIDの書き込み
*/
void addDbId(FilePage *pPage, nxpp::DbPtr dbPtr);
/**
* @brief データベース拡張割当情報の書き込み
*/
void addDbQuotaInfoExt(FilePage *pPage, nxpp::DbPtr dbPtr);
};
class DatabaseUpdater : public FilePage::Updater {
public:
virtual void operator ()(
FilePage *pPage,
nxpp::DbPtr dbPtr,
QStandardItem *item
) override;
};
#endif // DATABASEPAGE_H
データベースのローダーでは、タイトルなどのデータベース情報、データベースID、拡張割当情報などを表に追加できるようになっています。また、FilePage::Updaterから派生したDatabaseUpdaterクラスは、編集した内容をデータベースに書き込むことができます。
では、ソースファイルも見ていきます。
// filepage/databasepage.cpp
#include "databasepage.h"
#include <nxpp/qt/nxpp_qt_lmbcs.hpp>
#include <nxpp/nxpp_number.hpp>
#include <nxpp/qt/nxpp_qt_timedate.hpp>
#include <nxpp/nxpp_utils.hpp>
void DatabaseLoader::operator ()(FilePage *pPage, nxpp::DbPtr dbPtr) {
addPaths(pPage, dbPtr);
addDbInfo(pPage, dbPtr);
addDbId(pPage, dbPtr);
addDbQuotaInfoExt(pPage, dbPtr);
}
void DatabaseLoader::addDbInfo(FilePage *pPage, nxpp::DbPtr dbPtr) {
// DB情報を取得
auto dbInfo = dbPtr->getDbInfo();
// DB情報を格納するリストを作成
QMap<WORD, QPair<QString,QString>> list;
// DB情報の定数とラベルのマップデータを作成
const QMap<WORD, QString> map {
{ INFOPARSE_TITLE, pPage->tr("Title") },
{ INFOPARSE_CATEGORIES, pPage->tr("Categories") },
{ INFOPARSE_CLASS, pPage->tr("Class") },
{ INFOPARSE_DESIGN_CLASS, pPage->tr("Design Class") }
};
// DB情報の定数リストを作成
auto whats = map.keys();
// 定数リストを巡回
for (int i = 0; i < whats.length(); ++i) {
auto key = whats[i];
// DB情報から定数相当のデータを抽出
auto text = dbInfo.extract(key);
// モデルにキーとDB情報のパートデータを追加
auto items = pPage->addRowToMainModel(
map.value(key),
fromLmbcsQ(text)
);
// ラベルを編集不可にする
items.first->setEditable(false);
// ラベルアイテムのユーザーロールに識別子を登録(更新時に使用)
items.first->setData(QString("DbInfo/%1").arg(key));
}
}
void DatabaseLoader::addDbId(FilePage *pPage, nxpp::DbPtr dbPtr) {
// DBIDを取得
DBID dbid = dbPtr->getID();
// コンバーターを作成
nxpp::TimeDateToTextConverter converter;
// 日時フォーマットを作成
auto tfmt = std::make_shared<nxpp::TimeFormat>();
// タイムゾーンを常に表示
tfmt->setZone(TZFMT_ALWAYS);
// カスタムした日時フォーマットをコンバーターに設定
converter.setFormat(tfmt);
// DBIDを日時としてテキストに変換
auto timeDate = converter(&dbid);
// DBIDをバイナリテキストと日時でモデルに追加
auto items = pPage->addRowToMainModel(
"DBID",
QString("%1 (%2)")
.arg(QString::fromStdString(nxpp::hex(dbid, true)))
.arg(fromLmbcs(timeDate))
);
// ラベル、値ともに編集不可
items.first->setEditable(false);
items.second->setEditable(false);
}
void DatabaseLoader::addDbQuotaInfoExt(FilePage *pPage, nxpp::DbPtr dbPtr) {
// DBの拡張割当情報を取得
DBQUOTAINFOEXT quota = dbPtr->getQuotaInfoExt();
// 数値コンバーターを2つ作成
nxpp::NumberToTextConverter converter1, converter2;
// 数値フォーマットを2つ作成
auto nfmt1 = std::make_shared<nxpp::NumberFormat>();
auto nfmt2 = std::make_shared<nxpp::NumberFormat>();
// 1つ目の数値フォーマットを3桁区切りで設定
nfmt1->setPunctuated(true);
// 2つ目の数値フォーマットをバイト表示で設定
nfmt2->setFormat(NFMT_FIXED);
nfmt2->setBytes(true);
// 2つの数値フォーマットをそれぞれコンバーターに設定
converter1.setFormat(nfmt1);
converter2.setFormat(nfmt2);
// DBの拡張割当情報の各パートデータを取得
auto warnThreshold = static_cast<NUMBER>(quota.WarningThreshold);
auto sizeLimit = static_cast<NUMBER>(quota.SizeLimit);
auto currentDbSize = static_cast<NUMBER>(quota.CurrentDbSize);
auto maxDbSize = static_cast<NUMBER>(quota.MaxDbSize);
auto quotaMethod = static_cast<NUMBER>(quota.QuotaMethod);
auto currentUsage = static_cast<NUMBER>(quota.CurrentUsage);
auto currentSizeUsed = static_cast<NUMBER>(quota.CurrentSizeUsed);
// 各パートデータをマップ化
QVariantMap map {
{ pPage->tr("WarningThreshold"), fromLmbcsQ(converter1(&warnThreshold)) },
{ pPage->tr("SizeLimit"), fromLmbcsQ(converter1(&sizeLimit)) },
{ pPage->tr("CurrentDbSize"), fromLmbcsQ(converter1(¤tDbSize)) },
{ pPage->tr("MaxDbSize"), fromLmbcsQ(converter2(&maxDbSize)) },
{ pPage->tr("QuotaMethod"), fromLmbcsQ(converter1("aMethod)) },
{ pPage->tr("CurrentUsage"), fromLmbcsQ(converter1(¤tUsage)) },
{ pPage->tr("CurrentSizeUsed"), fromLmbcsQ(converter1(¤tSizeUsed)) }
};
// パートデータ毎にモデルに追加
for (auto key : map.keys()) {
auto items = pPage->addRowToMainModel(key, map.value(key));
items.first->setEditable(false);
items.second->setEditable(false);
}
}
void DatabaseUpdater::operator ()(
FilePage *pPage,
nxpp::DbPtr dbPtr,
QStandardItem *item
) {
// ページからモデルを取得
auto model = pPage->mainModel();
// 更新アイテムからインデックスを取得
QModelIndex index1 = model->indexFromItem(item);
// インデックスが2列目でなければ中止
if (index1.column() != 1) return;
// 同じ行の1列目(ラベル)を取得
QModelIndex index0 = model->index(index1.row(), 0);
QStandardItem *label = model->itemFromIndex(index0);
// 1列目のユーザーデータロールを取得
QString keyData = label->data().toString();
// データがDB情報を表していなければ中止
QRegExp rx(R"(DbInfo/(\d))");
if (!rx.exactMatch(keyData)) return;
// DB情報のパート定数を取得
uint type = rx.cap(1).toUInt();
// アイテムから更新されたテキストデータを取得
QString newData = item->data(Qt::EditRole).toString();
// DB情報を再取得
nxpp::DbInfo dbInfo = dbPtr->getDbInfo();
// DB情報を編集した内容で上書き
dbInfo.modify(type, toLmbcsQ(newData));
// DB情報を更新
dbPtr->setDbInfo(dbInfo);
// コンソール出力
emit pPage->consoleLog(
QString("Changed type: %1(%2) => %3")
.arg(type)
.arg(keyData)
.arg(newData)
);
}
まず、データベース情報については、こちらの記事でAPIを、こちらの記事でラッパークラスをご紹介しています。DBIDについてはこちらの記事やこちらの記事でご紹介しています。
データベースの拡張割当情報DBQUOTAINFOEXT構造体については、まだご紹介していないので、次回の記事で探訪してみたいと思います。
それでは、ここまでの実装を実演してみます(新しい箇所は未翻訳です)。
まとめ
Notes C APIを使って、データベース/ディレクトリの情報を取得し、データベース情報については、更新もすることができました。以前も書いたと思いますが、データベースタイトルについては、このアプリで変更しても、Notesクライアントのワークスペース上では変わっていません。デスクトップデータとしてキャッシュされていると思われます。
この記事が気に入ったらサポートをしてみませんか?