DOMブックマークアプリケーション
XML Bookmark Exchange Language ファイルのリーダーを提供します。
DOM Bookmarks Application は、XML Bookmark Exchange Language (XBEL) ファイル用のリーダーを提供します。このリーダーは、Qt の DOM ベースの XML API を使用してファイルを読み、解析します。QXmlStream Bookmarks Exampleでは、このタイプのファイルを読み取る別の方法を提供しています。
XbelTree クラスの定義
XbelTree クラスには、ファイルシステムに対する読み取りと書き込みの関数があります。QTreeWidget クラスを継承し、ブックマークを表示するためのモデルが含まれており、編集が可能です。
class XbelTree : public QTreeWidget { Q_OBJECT public: explicit XbelTree(QWidget *parent = nullptr); bool read(QIODevice *device); bool write(QIODevice *device) const; protected: #if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu) void contextMenuEvent(QContextMenuEvent *event) override; #endif private slots: void updateDomElement(const QTreeWidgetItem *item, int column); private: void parseFolderElement(const QDomElement &element, QTreeWidgetItem *parentItem = nullptr); QTreeWidgetItem *createItem(const QDomElement &element, QTreeWidgetItem *parentItem = nullptr); QDomDocument domDocument; QIcon folderIcon; QIcon bookmarkIcon; };
XbelTree クラスの実装
XbelTree
コンストラクタは、その中に配置されるQWidget を受け入れます。folderIcon
は QIcon::Normal モードに設定され、ユーザーがアイコンに触れていないときだけ pixmap が表示されます。QStyle::SP_DirClosedIcon 、QStyle::SP_DirOpenIcon 、QStyle::SP_FileIcon は、GUI のスタイルに従った標準的な pixmap に対応します。
XbelTree::XbelTree(QWidget *parent) : QTreeWidget(parent) { header()->setSectionResizeMode(QHeaderView::Stretch); setHeaderLabels({tr("Title"), tr("Location")}); folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal, QIcon::Off); folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On); bookmarkIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon)); }
read()
関数は、QDomDocument::setContent を使用して、指定されたQIODevice を開きます。ファイルを開くことに成功し、トップ・レベルのヘッダーが確認されると、ファイル・コンテンツが解析される前に、すべてのトップ・レベルのXMLノードを反復処理し、それらの各ノードでparseFolderElement()
を呼び出すことによって、クラスのコンテンツがクリアされます。
bool XbelTree::read(QIODevice *device) { QDomDocument::ParseResult result = domDocument.setContent(device, QDomDocument::ParseOption::UseNamespaceProcessing); if (!result) { QMessageBox::information(window(), tr("DOM Bookmarks"), tr("Parse error at line %1, column %2:\n%3") .arg(result.errorLine) .arg(result.errorColumn) .arg(result.errorMessage)); return false; } QDomElement root = domDocument.documentElement(); if (root.tagName() != "xbel") { QMessageBox::information(window(), tr("DOM Bookmarks"), tr("The file is not an XBEL file.")); return false; } else if (root.hasAttribute(versionAttribute) && root.attribute(versionAttribute) != "1.0"_L1) { QMessageBox::information(window(), tr("DOM Bookmarks"), tr("The file is not an XBEL version 1.0 " "file.")); return false; } clear(); disconnect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement); QDomElement child = root.firstChildElement(folderElement); while (!child.isNull()) { parseFolderElement(child); child = child.nextSiblingElement(folderElement); } connect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement); return true; }
parseFolderElement()
関数はさまざまな要素タイプを処理し、要素がサブフォルダの場合は再帰的に呼び出します。
void XbelTree::parseFolderElement(const QDomElement &element, QTreeWidgetItem *parentItem) { QTreeWidgetItem *item = createItem(element, parentItem); QString title = element.firstChildElement(titleElement).text(); if (title.isEmpty()) title = tr("Folder"); item->setFlags(item->flags() | Qt::ItemIsEditable); item->setIcon(0, folderIcon); item->setText(0, title); bool folded = (element.attribute(foldedAttribute) != "no"_L1); item->setExpanded(!folded); constexpr char16_t midDot = u'\xB7'; static const QString dots = QString(30, midDot); QDomElement child = element.firstChildElement(); while (!child.isNull()) { if (child.tagName() == folderElement) { parseFolderElement(child, item); } else if (child.tagName() == bookmarkElement) { QTreeWidgetItem *childItem = createItem(child, item); QString title = child.firstChildElement(titleElement).text(); if (title.isEmpty()) title = tr("Folder"); childItem->setFlags(item->flags() | Qt::ItemIsEditable); childItem->setIcon(0, bookmarkIcon); childItem->setText(0, title); childItem->setText(1, child.attribute(hrefAttribute)); } else if (child.tagName() == "separator"_L1) { QTreeWidgetItem *childItem = createItem(child, item); childItem->setFlags(item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsEditable)); childItem->setText(0, dots); } child = child.nextSiblingElement(); } }
write()
関数は、QDomDocument::save を使用して、指定されたQIODevice に domDocument を保存します。
bool XbelTree::write(QIODevice *device) const { const int IndentSize = 4; QTextStream out(device); domDocument.save(out, IndentSize); return true; }
MainWindow クラスの定義
MainWindow
クラスはQMainWindow のサブクラスで、File
メニューとHelp
メニューがあります。
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); public slots: void open(); void saveAs(); void about(); private: void createMenus(); XbelTree *xbelTree; };
MainWindow クラスの実装
MainWindow
コンストラクタは、メンバである XbelTree オブジェクトをインスタンス化し、そのヘッダをQStringList オブジェクトlabels
で設定します。また、コンストラクタはcreateMenus()
を呼び出してメニューを設定します。statusBar()
は、"Ready "というメッセージを表示するために使用されます。
MainWindow::MainWindow() { xbelTree = new XbelTree; setCentralWidget(xbelTree); createMenus(); statusBar()->showMessage(tr("Ready")); setWindowTitle(tr("DOM Bookmarks")); const QSize availableSize = screen()->availableGeometry().size(); resize(availableSize.width() / 2, availableSize.height() / 3); }
createMenus()
関数はメニューの入力とキーボードショートカットの設定を行います。
void MainWindow::createMenus() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open); openAct->setShortcuts(QKeySequence::Open); QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs); saveAsAct->setShortcuts(QKeySequence::SaveAs); QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close); exitAct->setShortcuts(QKeySequence::Quit); menuBar()->addSeparator(); QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(tr("&About"), this, &MainWindow::about); helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); }
open()
関数を使用すると、QFileDialog を使用して XBEL ファイルを開くことができます。ファイルが読み込めない場合やパース・エラーの場合は、fileName
とerrorString
とともに警告メッセージが表示されます。成功した場合はXbelTree::read()
を呼び出す。
void MainWindow::open() { QFileDialog fileDialog(this, tr("Open Bookmark File"), QDir::currentPath()); fileDialog.setMimeTypeFilters({"application/x-xbel"_L1}); if (fileDialog.exec() != QDialog::Accepted) return; const QString fileName = fileDialog.selectedFiles().constFirst(); QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning(this, tr("DOM Bookmarks"), tr("Cannot read file %1:\n%2.") .arg(QDir::toNativeSeparators(fileName), file.errorString())); return; } if (xbelTree->read(&file)) statusBar()->showMessage(tr("File loaded"), 2000); }
saveAs()
関数は、QFileDialog を表示し、ユーザーにfileName
を要求します。open()
関数と同様に、この関数もファイルに書き込めなかった場合に警告メッセージを表示します。これが成功すると、XbelTree::write()
を呼び出します。
void MainWindow::saveAs() { QFileDialog fileDialog(this, tr("Save Bookmark File"), QDir::currentPath()); fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setDefaultSuffix("xbel"_L1); fileDialog.setMimeTypeFilters({"application/x-xbel"_L1}); if (fileDialog.exec() != QDialog::Accepted) return; const QString fileName = fileDialog.selectedFiles().constFirst(); QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(this, tr("DOM Bookmarks"), tr("Cannot write file %1:\n%2.") .arg(QDir::toNativeSeparators(fileName), file.errorString())); return; } if (xbelTree->write(&file)) statusBar()->showMessage(tr("File saved"), 2000); }
about()
関数は、例の簡単な説明とともにQMessageBox を表示する。
void MainWindow::about() { QMessageBox::about(this, tr("About DOM Bookmarks"), tr("The <b>DOM Bookmarks</b> example demonstrates how to " "use Qt's DOM classes to read and write XML " "documents.")); }
XBELファイルの詳細については、XML Bookmark Exchange Language Resource Pageを参照してください。
本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。