Brush up the DOM bookmarks example

- Use modern string literals (use QStringLiteral instead of
  QLatin1StringView for strings that go into the DOM API).
- Use mime types in the file dialog handling
- Streamline code
- Remove mentions of SAX
- Use per class includes
- Do not use QObject::tr()
- Use the configure system instead of QT_NO... defines
- Fix some doc text typos

Complements 3dd3268ded4dd74c64d7ec726fd534375ab9f018.

Task-number: QTBUG-111974
Change-Id: If0dc7b61e729d0a71f37743efc9b82e285d3f451
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 3a553507a134bee1562d34ebbf786a053d36fc05)
This commit is contained in:
Friedemann Kleint 2023-06-12 11:48:21 +02:00
parent 919d479142
commit 9e85c70b37
4 changed files with 72 additions and 54 deletions

View File

@ -20,7 +20,7 @@
The XbelTree class has functions for reading and writing to the filesystem.
It inherits from the QTreeWidget class, contains the model for the
dispalying of the bookmarks, and allows it to be edited.
displaying of the bookmarks, and allows it to be edited.
\snippet dombookmarks/xbeltree.h 0
@ -68,23 +68,22 @@
\snippet dombookmarks/mainwindow.cpp 0
The \c createMenus() function poulates the menus and sets keyboard
The \c createMenus() function populates the menus and sets keyboard
shortcuts.
\snippet dombookmarks/mainwindow.cpp 4
The \c open() function enables the user to open an XBEL file using
QFileDialog::getOpenFileName(). A warning message is displayed along
QFileDialog. A warning message is displayed along
with the \c fileName and \c errorString if the file cannot be read or
if there is a parse error. If it succeeds it calls \c XbelTree::read().
\snippet dombookmarks/mainwindow.cpp 1
The \c saveAs() function displays a QFileDialog, prompting the user for
a \c fileName using QFileDialog::getSaveFileName(). Similar to the
\c open() function, this function also displays a warning message if
the file cannot be written to. IF this succeeds it calls \c
XbelTree::write().
a \c fileName. Similar to the \c open() function, this function also
displays a warning message if the file cannot be written to. If this
succeeds it calls \c XbelTree::write().
\snippet dombookmarks/mainwindow.cpp 2

View File

@ -1,11 +1,20 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "mainwindow.h"
#include "xbeltree.h"
#include <QApplication>
#include <QFileDialog>
#include <QMenuBar>
#include <QMessageBox>
#include <QStatusBar>
#include <QAction>
#include <QScreen>
using namespace Qt::StringLiterals;
//! [0]
MainWindow::MainWindow()
{
@ -25,16 +34,15 @@ MainWindow::MainWindow()
//! [1]
void MainWindow::open()
{
QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Bookmark File"),
QDir::currentPath(),
tr("XBEL Files (*.xbel *.xml)"));
if (fileName.isEmpty())
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("SAX Bookmarks"),
QMessageBox::warning(this, tr("DOM Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
@ -49,16 +57,17 @@ void MainWindow::open()
//! [2]
void MainWindow::saveAs()
{
QString fileName =
QFileDialog::getSaveFileName(this, tr("Save Bookmark File"),
QDir::currentPath(),
tr("XBEL Files (*.xbel *.xml)"));
if (fileName.isEmpty())
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("SAX Bookmarks"),
QMessageBox::warning(this, tr("DOM Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));

View File

@ -1,31 +1,41 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "xbeltree.h"
#include <QHeaderView>
#include <QMenu>
#include <QMessageBox>
#include <QDesktopServices>
#include <QGuiApplication>
#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
# include <QClipboard>
# include <QContextMenuEvent>
#endif
#include <QUrl>
using namespace Qt::StringLiterals;
enum { DomElementRole = Qt::UserRole + 1 };
Q_DECLARE_METATYPE(QDomElement)
static inline QString titleElement() { return QStringLiteral("title"); }
static inline QString folderElement() { return QStringLiteral("folder"); }
static inline QString bookmarkElement() { return QStringLiteral("bookmark"); }
static const auto titleElement = u"title"_s;
static const auto folderElement = u"folder"_s;
static const auto bookmarkElement = u"bookmark"_s;
static inline QString versionAttribute() { return QStringLiteral("version"); }
static inline QString hrefAttribute() { return QStringLiteral("href"); }
static inline QString foldedAttribute() { return QStringLiteral("folded"); }
static const auto versionAttribute = u"version"_s;
static const auto hrefAttribute = u"href"_s;
static const auto foldedAttribute = u"folded"_s;
//! [0]
XbelTree::XbelTree(QWidget *parent)
: QTreeWidget(parent)
{
QStringList labels;
labels << tr("Title") << tr("Location");
header()->setSectionResizeMode(QHeaderView::Stretch);
setHeaderLabels(labels);
setHeaderLabels({tr("Title"), tr("Location")});
folderIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
QIcon::Normal, QIcon::Off);
@ -35,7 +45,7 @@ XbelTree::XbelTree(QWidget *parent)
}
//! [0]
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
void XbelTree::contextMenuEvent(QContextMenuEvent *event)
{
const QTreeWidgetItem *item = itemAt(event->pos());
@ -51,7 +61,7 @@ void XbelTree::contextMenuEvent(QContextMenuEvent *event)
else if (action == openAction)
QDesktopServices::openUrl(QUrl(url));
}
#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
#endif // QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
//! [1]
bool XbelTree::read(QIODevice *device)
@ -72,8 +82,8 @@ bool XbelTree::read(QIODevice *device)
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL file."));
return false;
} else if (root.hasAttribute(versionAttribute())
&& root.attribute(versionAttribute()) != QLatin1String("1.0")) {
} 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."));
@ -84,10 +94,10 @@ bool XbelTree::read(QIODevice *device)
disconnect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
QDomElement child = root.firstChildElement(folderElement());
QDomElement child = root.firstChildElement(folderElement);
while (!child.isNull()) {
parseFolderElement(child);
child = child.nextSiblingElement(folderElement());
child = child.nextSiblingElement(folderElement);
}
connect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
@ -112,16 +122,16 @@ void XbelTree::updateDomElement(const QTreeWidgetItem *item, int column)
QDomElement element = qvariant_cast<QDomElement>(item->data(0, DomElementRole));
if (!element.isNull()) {
if (column == 0) {
QDomElement oldTitleElement = element.firstChildElement(titleElement());
QDomElement newTitleElement = domDocument.createElement(titleElement());
QDomElement oldTitleElement = element.firstChildElement(titleElement);
QDomElement newTitleElement = domDocument.createElement(titleElement);
QDomText newTitleText = domDocument.createTextNode(item->text(0));
newTitleElement.appendChild(newTitleText);
element.replaceChild(newTitleElement, oldTitleElement);
} else {
if (element.tagName() == bookmarkElement())
element.setAttribute(hrefAttribute(), item->text(1));
if (element.tagName() == bookmarkElement)
element.setAttribute(hrefAttribute, item->text(1));
}
}
}
@ -132,35 +142,35 @@ void XbelTree::parseFolderElement(const QDomElement &element,
{
QTreeWidgetItem *item = createItem(element, parentItem);
QString title = element.firstChildElement(titleElement()).text();
QString title = element.firstChildElement(titleElement).text();
if (title.isEmpty())
title = QObject::tr("Folder");
title = tr("Folder");
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, folderIcon);
item->setText(0, title);
bool folded = (element.attribute(foldedAttribute()) != QLatin1String("no"));
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()) {
if (child.tagName() == folderElement) {
parseFolderElement(child, item);
} else if (child.tagName() == bookmarkElement()) {
} else if (child.tagName() == bookmarkElement) {
QTreeWidgetItem *childItem = createItem(child, item);
QString title = child.firstChildElement(titleElement()).text();
QString title = child.firstChildElement(titleElement).text();
if (title.isEmpty())
title = QObject::tr("Folder");
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() == QLatin1String("separator")) {
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);

View File

@ -14,13 +14,13 @@ class XbelTree : public QTreeWidget
Q_OBJECT
public:
XbelTree(QWidget *parent = nullptr);
explicit XbelTree(QWidget *parent = nullptr);
bool read(QIODevice *device);
bool write(QIODevice *device) const;
protected:
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
void contextMenuEvent(QContextMenuEvent *event) override;
#endif