NotesとQtでWindows、Mac OS X、Ubuntuのデスクトップアプリ(その8 - データベース・基本クラス編)

前回紹介したデータベース関連のAPIを踏まえて、Databaseクラスを定義していきます。 方針としては、Notes/Domino APIプログラミング―C++とSTLによる実践的プログラミングを踏襲して、コピー不可のクラスとします。

<database.h>

#ifndef NTLX_DATABASE_H
#define NTLX_DATABASE_H

#include "ntlx_global.h"
#include <QString>
#include "status.h"

#if defined(NT)
#pragma pack(push, 1)
#endif

#include <nsfdb.h>

#if defined(NT)
#pragma pack(pop)
#endif

namespace ntlx {

class Lmbcs;

/**
 * @brief データベースクラス
 */
class NTLXSHARED_EXPORT Database
{
public:
  /**
   * @brief デフォルトコンストラクタ
   */
  explicit Database();

  /**
   * @brief パスによるコンストラクタ
   * @param path パス
   * @param server サーバ名(省略時はローカル)
   * @param port ポート名(省略時はデフォルトポート)
   */
  explicit Database(const QString& path
                    , const QString& server = QString()
                    , const QString& port = QString()
                    , Status* status = nullptr
      );

  /**
   * @brief デストラクタ
   */
  virtual ~Database();

  /**
   * @brief DBHANDLEキャスト演算子
   */
  operator DBHANDLE() const { return handle_; }

  /**
   * @brief データベースのタイトルを取得する
   * @param status 関数の実行結果を取得したい場合はSTATUS変数へのポインタ
   * @return データベースタイトル
   */
  QString getTitle(STATUS* status = nullptr) const;

  /**
   * @brief データベースカテゴリ名を取得する
   * @param status 関数の実行結果を取得したい場合はSTATUS変数へのポインタ
   * @return データベースカテゴリ名
   */
  QString getCategories(STATUS* status = nullptr) const;

  /**
   * @brief データベースクラス(引き継ぎ元テンプレート名)を取得する
   * @param status 関数の実行結果を取得したい場合はSTATUS変数へのポインタ
   * @return データベースクラス(引き継ぎ元テンプレート名)
   */
  QString getClass(STATUS* status = nullptr) const;

  /**
   * @brief データベース設計クラス(自身のテンプレート名)を取得する
   * @param status 関数の実行結果を取得したい場合はSTATUS変数へのポインタ
   * @return データベース設計クラス(自身のテンプレート名)
   */
  QString getDesignClass(STATUS* status = nullptr) const;

  /**
   * @brief データベースを開く
   * @return 結果ステータス
   */
  Status open(
      const QString& path
      , const QString& server
      , const QString& port
      );

  /**
   * @brief データベースを閉じる
   * @return 結果ステータス
   */
  Status close();

  /**
   * @brief パス、サーバ名、ポート名からネットパスを構築する
   * @param path パス
   * @param server サーバ名
   * @param port ポート名
   * @param status 結果ステータス
   * @return ネットパス
   */
  static Lmbcs constructNetPath(
      const QString& path
      , const QString& server
      , const QString& port
      , STATUS* status = nullptr
      );

protected:
  /**
   * @brief データベースハンドルを返す
   * @return データベースハンドル
   */
  DBHANDLE handle() const { return handle_; }

  /**
   * @brief ハンドルを設定する
   * @param handle データベースハンドル
   */
  void setHandle(DBHANDLE handle) { handle_ = handle; }

  /**
   * @brief データベース情報を取得する
   * @param what データベース情報の種類(INFOPARSE_XXX)
   * @param status 結果ステータス
   * @return データベース情報
   */
  QString getInfo(WORD what, STATUS* status = nullptr) const;

private:
  DBHANDLE handle_;

  Database(const Database&);
  Database& operator=(const Database&);
};

} // namespace ntlx

#endif // NTLX_DATABASE_H



<database.cpp>

#include "database.h"
#include "lmbcs.h"

#if defined(NT)
#pragma pack(push, 1)
#endif

#include <osfile.h>

#if defined(NT)
#pragma pack(pop)
#endif

namespace ntlx {

Database::Database()
  : handle_(NULLHANDLE)
{
}

Database::Database(const QString &path
                   , const QString &server
                   , const QString &port
                   , Status* status
                   )
  : handle_(NULLHANDLE)
{
  Status result = open(path, server, port);
  if (status != nullptr) *status = result;
}

Database::~Database()
{
  close();
}

QString Database::getTitle(STATUS* status) const
{
  return getInfo(INFOPARSE_TITLE, status);
}

QString Database::getCategories(STATUS* status) const
{
  return getInfo(INFOPARSE_CATEGORIES, status);
}

QString Database::getClass(STATUS* status) const
{
  return getInfo(INFOPARSE_CLASS, status);
}

QString Database::getDesignClass(STATUS* status) const
{
  return getInfo(INFOPARSE_DESIGN_CLASS, status);
}

Status Database::open(
    const QString& path
    , const QString& server
    , const QString& port
    )
{
  close();

  Lmbcs netPath = constructNetPath(path, server, port);
  Status result = NSFDbOpen(netPath.constData(), &handle_);
  if (result.failure()) handle_ = NULLHANDLE;
  return result;
}

Status Database::close()
{
  if (handle_ != NULLHANDLE)
  {
    Status result = NSFDbClose(handle_);
    handle_ = NULLHANDLE;
    return result;
  }
  return NOERROR;
}

Lmbcs Database::constructNetPath(const QString &path
                                 , const QString &server
                                 , const QString &port
                                 , STATUS* status
                                 )
{
  Lmbcs lmPath = Lmbcs::fromQString(path);
  Lmbcs lmServer = Lmbcs::fromQString(server);
  Lmbcs lmPort = Lmbcs::fromQString(port);
  char netPath[MAXPATH];

  Status result = OSPathNetConstruct(
        lmPort.isEmpty() ? 0 : lmPort.constData()
        , lmServer.constData()
        , lmPath.constData()
        , netPath
        );
  if (status != nullptr) *status = result;

  return result.success() ? Lmbcs(netPath) : Lmbcs();
}

/**
 * @note NSF_INFOは以下のような構成を取る
 * @note タイトル+改行+カテゴリ+改行+#1+設計クラス+改行+#2+クラス+終端0
 * @note 全体で128バイト以内になる
 */
QString Database::getInfo(WORD what, STATUS* status) const
{
  Q_ASSERT(handle());

  char infoData[NSF_INFO_SIZE];
  char nameData[NSF_INFO_SIZE];

  Status result = NSFDbInfoGet(handle(), infoData);
  if (status != nullptr)
    *status = result;

  if (result.failure())
    return QString();

  NSFDbInfoParse(infoData, what, nameData, NSF_INFO_SIZE - 1);
  nameData[NSF_INFO_SIZE - 1] = '\0';
  Lmbcs lmbcs(nameData);
  return lmbcs.toQString();
}

} // namespace ntlx