Polish the XML bookmarks examples

- Use Qt 5 connect syntax.
- Streamline code, remove unused members.
- Add a context menu for copying and opening the URLs.
- Add const to XML code.
- In the XML code, show the use of QStringLiteral in static inline
  functions to create strings versus QLatin1String in comparison
  overloads to avoid allocating strings from const char * literals.

Change-Id: Ib5e62ca188e271ffe01996dff3c9ea8e0b60739a
Reviewed-by: Topi Reiniö <topi.reinio@qt.io>
This commit is contained in:
Friedemann Kleint 2016-10-31 11:09:00 +01:00
parent 146f6d261b
commit 8d71fae080
16 changed files with 238 additions and 219 deletions

View File

@ -58,13 +58,13 @@ MainWindow::MainWindow()
xbelTree = new XbelTree;
setCentralWidget(xbelTree);
createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("DOM Bookmarks"));
resize(480, 320);
const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
resize(availableSize.width() / 2, availableSize.height() / 3);
}
void MainWindow::open()
@ -80,8 +80,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -102,8 +102,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -119,37 +119,21 @@ void MainWindow::about()
"documents."));
}
void MainWindow::createActions()
{
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
saveAsAct = new QAction(tr("&Save As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAct);
fileMenu->addAction(saveAsAct);
fileMenu->addAction(exitAct);
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();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}

View File

@ -68,18 +68,9 @@ public slots:
void about();
private:
void createActions();
void createMenus();
XbelTree *xbelTree;
QMenu *fileMenu;
QMenu *helpMenu;
QAction *openAct;
QAction *saveAsAct;
QAction *exitAct;
QAction *aboutAct;
QAction *aboutQtAct;
};
#endif

View File

@ -52,6 +52,18 @@
#include "xbeltree.h"
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 inline QString versionAttribute() { return QStringLiteral("version"); }
static inline QString hrefAttribute() { return QStringLiteral("href"); }
static inline QString foldedAttribute() { return QStringLiteral("folded"); }
XbelTree::XbelTree(QWidget *parent)
: QTreeWidget(parent)
{
@ -68,6 +80,24 @@ XbelTree::XbelTree(QWidget *parent)
bookmarkIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
}
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void XbelTree::contextMenuEvent(QContextMenuEvent *event)
{
const QTreeWidgetItem *item = itemAt(event->pos());
if (!item)
return;
const QString url = item->text(1);
QMenu contextMenu;
QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
QAction *openAction = contextMenu.addAction(tr("Open"));
QAction *action = contextMenu.exec(event->globalPos());
if (action == copyAction)
QGuiApplication::clipboard()->setText(url);
else if (action == openAction)
QDesktopServices::openUrl(QUrl(url));
}
#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
bool XbelTree::read(QIODevice *device)
{
QString errorStr;
@ -89,8 +119,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("version")
&& root.attribute("version") != "1.0") {
} else if (root.hasAttribute(versionAttribute())
&& root.attribute(versionAttribute()) != QLatin1String("1.0")) {
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL version 1.0 "
"file."));
@ -99,22 +129,20 @@ bool XbelTree::read(QIODevice *device)
clear();
disconnect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
disconnect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
QDomElement child = root.firstChildElement("folder");
QDomElement child = root.firstChildElement(folderElement());
while (!child.isNull()) {
parseFolderElement(child);
child = child.nextSiblingElement("folder");
child = child.nextSiblingElement(folderElement());
}
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
connect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
return true;
}
bool XbelTree::write(QIODevice *device)
bool XbelTree::write(QIODevice *device) const
{
const int IndentSize = 4;
@ -123,21 +151,21 @@ bool XbelTree::write(QIODevice *device)
return true;
}
void XbelTree::updateDomElement(QTreeWidgetItem *item, int column)
void XbelTree::updateDomElement(const QTreeWidgetItem *item, int column)
{
QDomElement element = domElementForItem.value(item);
QDomElement element = item->data(0, DomElementRole).value<QDomElement>();
if (!element.isNull()) {
if (column == 0) {
QDomElement oldTitleElement = element.firstChildElement("title");
QDomElement newTitleElement = domDocument.createElement("title");
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() == "bookmark")
element.setAttribute("href", item->text(1));
if (element.tagName() == bookmarkElement())
element.setAttribute(hrefAttribute(), item->text(1));
}
}
}
@ -147,7 +175,7 @@ void XbelTree::parseFolderElement(const QDomElement &element,
{
QTreeWidgetItem *item = createItem(element, parentItem);
QString title = element.firstChildElement("title").text();
QString title = element.firstChildElement(titleElement()).text();
if (title.isEmpty())
title = QObject::tr("Folder");
@ -155,25 +183,25 @@ void XbelTree::parseFolderElement(const QDomElement &element,
item->setIcon(0, folderIcon);
item->setText(0, title);
bool folded = (element.attribute("folded") != "no");
bool folded = (element.attribute(foldedAttribute()) != QLatin1String("no"));
setItemExpanded(item, !folded);
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
if (child.tagName() == "folder") {
if (child.tagName() == folderElement()) {
parseFolderElement(child, item);
} else if (child.tagName() == "bookmark") {
} else if (child.tagName() == bookmarkElement()) {
QTreeWidgetItem *childItem = createItem(child, item);
QString title = child.firstChildElement("title").text();
QString title = child.firstChildElement(titleElement()).text();
if (title.isEmpty())
title = QObject::tr("Folder");
childItem->setFlags(item->flags() | Qt::ItemIsEditable);
childItem->setIcon(0, bookmarkIcon);
childItem->setText(0, title);
childItem->setText(1, child.attribute("href"));
} else if (child.tagName() == "separator") {
childItem->setText(1, child.attribute(hrefAttribute()));
} else if (child.tagName() == QLatin1String("separator")) {
QTreeWidgetItem *childItem = createItem(child, item);
childItem->setFlags(item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsEditable));
childItem->setText(0, QString(30, 0xB7));
@ -191,6 +219,6 @@ QTreeWidgetItem *XbelTree::createItem(const QDomElement &element,
} else {
item = new QTreeWidgetItem(this);
}
domElementForItem.insert(item, element);
item->setData(0, DomElementRole, QVariant::fromValue(element));
return item;
}

View File

@ -52,7 +52,6 @@
#define XBELTREE_H
#include <QDomDocument>
#include <QHash>
#include <QIcon>
#include <QTreeWidget>
@ -64,10 +63,15 @@ public:
XbelTree(QWidget *parent = 0);
bool read(QIODevice *device);
bool write(QIODevice *device);
bool write(QIODevice *device) const;
protected:
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
#endif
private slots:
void updateDomElement(QTreeWidgetItem *item, int column);
void updateDomElement(const QTreeWidgetItem *item, int column);
private:
void parseFolderElement(const QDomElement &element,
@ -76,7 +80,6 @@ private:
QTreeWidgetItem *parentItem = 0);
QDomDocument domDocument;
QHash<QTreeWidgetItem *, QDomElement> domElementForItem;
QIcon folderIcon;
QIcon bookmarkIcon;
};

View File

@ -62,17 +62,40 @@ MainWindow::MainWindow()
treeWidget = new QTreeWidget;
treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
treeWidget->setHeaderLabels(labels);
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeWidget, &QWidget::customContextMenuRequested,
this, &MainWindow::onCustomContextMenuRequested);
#endif
setCentralWidget(treeWidget);
createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("SAX Bookmarks"));
resize(480, 320);
const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
resize(availableSize.width() / 2, availableSize.height() / 3);
}
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
{
const QTreeWidgetItem *item = treeWidget->itemAt(pos);
if (!item)
return;
const QString url = item->text(1);
QMenu contextMenu;
QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
QAction *openAction = contextMenu.addAction(tr("Open"));
QAction *action = contextMenu.exec(treeWidget->viewport()->mapToGlobal(pos));
if (action == copyAction)
QGuiApplication::clipboard()->setText(url);
else if (action == openAction)
QDesktopServices::openUrl(QUrl(url));
}
#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
void MainWindow::open()
{
QString fileName =
@ -93,8 +116,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -116,8 +139,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -134,37 +157,21 @@ void MainWindow::about()
"hand."));
}
void MainWindow::createActions()
{
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
saveAsAct = new QAction(tr("&Save As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAct);
fileMenu->addAction(saveAsAct);
fileMenu->addAction(exitAct);
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();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}

View File

@ -68,20 +68,13 @@ public slots:
void open();
void saveAs();
void about();
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void onCustomContextMenuRequested(const QPoint &pos);
#endif
private:
void createActions();
void createMenus();
QTreeWidget *treeWidget;
QMenu *fileMenu;
QMenu *helpMenu;
QAction *openAct;
QAction *saveAsAct;
QAction *exitAct;
QAction *aboutAct;
QAction *aboutQtAct;
};
#endif

View File

@ -52,7 +52,7 @@
#include "xbelgenerator.h"
XbelGenerator::XbelGenerator(QTreeWidget *treeWidget)
XbelGenerator::XbelGenerator(const QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
}
@ -81,25 +81,25 @@ QString XbelGenerator::indent(int depth)
QString XbelGenerator::escapedText(const QString &str)
{
QString result = str;
result.replace("&", "&amp;");
result.replace("<", "&lt;");
result.replace(">", "&gt;");
result.replace('&', "&amp;");
result.replace('<', "&lt;");
result.replace('>', "&gt;");
return result;
}
QString XbelGenerator::escapedAttribute(const QString &str)
{
QString result = escapedText(str);
result.replace("\"", "&quot;");
result.replace(QLatin1Char('"'), "&quot;");
result.prepend(QLatin1Char('"'));
result.append(QLatin1Char('"'));
return result;
}
void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
void XbelGenerator::generateItem(const QTreeWidgetItem *item, int depth)
{
QString tagName = item->data(0, Qt::UserRole).toString();
if (tagName == "folder") {
if (tagName == QLatin1String("folder")) {
bool folded = !treeWidget->isItemExpanded(item);
out << indent(depth) << "<folder folded=\"" << (folded ? "yes" : "no")
<< "\">\n"
@ -110,7 +110,7 @@ void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
generateItem(item->child(i), depth + 1);
out << indent(depth) << "</folder>\n";
} else if (tagName == "bookmark") {
} else if (tagName == QLatin1String("bookmark")) {
out << indent(depth) << "<bookmark";
if (!item->text(1).isEmpty())
out << " href=" << escapedAttribute(item->text(1));
@ -118,7 +118,7 @@ void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
<< indent(depth + 1) << "<title>" << escapedText(item->text(0))
<< "</title>\n"
<< indent(depth) << "</bookmark>\n";
} else if (tagName == "separator") {
} else if (tagName == QLatin1String("separator")) {
out << indent(depth) << "<separator/>\n";
}
}

View File

@ -61,7 +61,7 @@ QT_END_NAMESPACE
class XbelGenerator
{
public:
XbelGenerator(QTreeWidget *treeWidget);
explicit XbelGenerator(const QTreeWidget *treeWidget);
bool write(QIODevice *device);
@ -69,9 +69,9 @@ private:
static QString indent(int indentLevel);
static QString escapedText(const QString &str);
static QString escapedAttribute(const QString &str);
void generateItem(QTreeWidgetItem *item, int depth);
void generateItem(const QTreeWidgetItem *item, int depth);
QTreeWidget *treeWidget;
const QTreeWidget *treeWidget;
QTextStream out;
};

View File

@ -52,6 +52,10 @@
#include "xbelhandler.h"
static inline QString versionAttribute() { return QStringLiteral("version"); }
static inline QString hrefAttribute() { return QStringLiteral("href"); }
static inline QString foldedAttribute() { return QStringLiteral("folded"); }
XbelHandler::XbelHandler(QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
@ -72,32 +76,32 @@ bool XbelHandler::startElement(const QString & /* namespaceURI */,
const QString &qName,
const QXmlAttributes &attributes)
{
if (!metXbelTag && qName != "xbel") {
if (!metXbelTag && qName != QLatin1String("xbel")) {
errorStr = QObject::tr("The file is not an XBEL file.");
return false;
}
if (qName == "xbel") {
QString version = attributes.value("version");
if (!version.isEmpty() && version != "1.0") {
if (qName == QLatin1String("xbel")) {
QString version = attributes.value(versionAttribute());
if (!version.isEmpty() && version != QLatin1String("1.0")) {
errorStr = QObject::tr("The file is not an XBEL version 1.0 file.");
return false;
}
metXbelTag = true;
} else if (qName == "folder") {
} else if (qName == QLatin1String("folder")) {
item = createChildItem(qName);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, folderIcon);
item->setText(0, QObject::tr("Folder"));
bool folded = (attributes.value("folded") != "no");
bool folded = (attributes.value(foldedAttribute()) != QLatin1String("no"));
treeWidget->setItemExpanded(item, !folded);
} else if (qName == "bookmark") {
} else if (qName == QLatin1String("bookmark")) {
item = createChildItem(qName);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, bookmarkIcon);
item->setText(0, QObject::tr("Unknown title"));
item->setText(1, attributes.value("href"));
} else if (qName == "separator") {
item->setText(1, attributes.value(hrefAttribute()));
} else if (qName == QLatin1String("separator")) {
item = createChildItem(qName);
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
item->setText(0, QString(30, 0xB7));
@ -111,11 +115,11 @@ bool XbelHandler::endElement(const QString & /* namespaceURI */,
const QString & /* localName */,
const QString &qName)
{
if (qName == "title") {
if (qName == QLatin1String("title")) {
if (item)
item->setText(0, currentText);
} else if (qName == "folder" || qName == "bookmark"
|| qName == "separator") {
} else if (qName == QLatin1String("folder") || qName == QLatin1String("bookmark")
|| qName == QLatin1String("separator")) {
item = item->parent();
}
return true;

View File

@ -167,7 +167,7 @@
add them to the \c fileMenu and \c helpMenu. The connections are as shown
below:
\snippet streambookmarks/mainwindow.cpp 4
\snippet streambookmarks/mainwindow.cpp 5
The \c createMenus() function creates the \c fileMenu and \c helpMenu
and adds the QAction objects to them in order to create the menu shown

View File

@ -63,18 +63,41 @@ MainWindow::MainWindow()
treeWidget = new QTreeWidget;
treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
treeWidget->setHeaderLabels(labels);
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeWidget, &QWidget::customContextMenuRequested,
this, &MainWindow::onCustomContextMenuRequested);
#endif
setCentralWidget(treeWidget);
createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("QXmlStream Bookmarks"));
resize(480, 320);
const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
resize(availableSize.width() / 2, availableSize.height() / 3);
}
//! [0]
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
{
const QTreeWidgetItem *item = treeWidget->itemAt(pos);
if (!item)
return;
const QString url = item->text(1);
QMenu contextMenu;
QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
QAction *openAction = contextMenu.addAction(tr("Open"));
QAction *action = contextMenu.exec(treeWidget->viewport()->mapToGlobal(pos));
if (action == copyAction)
QGuiApplication::clipboard()->setText(url);
else if (action == openAction)
QDesktopServices::openUrl(QUrl(url));
}
#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
//! [1]
void MainWindow::open()
{
@ -92,8 +115,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot read file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -101,8 +124,8 @@ void MainWindow::open()
if (!reader.read(&file)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Parse error in file %1:\n\n%2")
.arg(fileName)
.arg(reader.errorString()));
.arg(QDir::toNativeSeparators(fileName),
reader.errorString()));
} else {
statusBar()->showMessage(tr("File loaded"), 2000);
}
@ -124,8 +147,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot write file %1:\n%2.")
.arg(fileName)
.arg(file.errorString()));
.arg(QDir::toNativeSeparators(fileName),
file.errorString()));
return;
}
@ -144,41 +167,23 @@ void MainWindow::about()
}
//! [3]
//! [4]
void MainWindow::createActions()
{
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
saveAsAct = new QAction(tr("&Save As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
//! [4]
//! [5]
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAct);
fileMenu->addAction(saveAsAct);
fileMenu->addAction(exitAct);
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();
helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}
//! [5]

View File

@ -69,20 +69,13 @@ public slots:
void open();
void saveAs();
void about();
#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
void onCustomContextMenuRequested(const QPoint &pos);
#endif
private:
void createActions();
void createMenus();
QTreeWidget *treeWidget;
QMenu *fileMenu;
QMenu *helpMenu;
QAction *openAct;
QAction *saveAsAct;
QAction *exitAct;
QAction *aboutAct;
QAction *aboutQtAct;
};
//! [0]

View File

@ -72,10 +72,12 @@ bool XbelReader::read(QIODevice *device)
xml.setDevice(device);
if (xml.readNextStartElement()) {
if (xml.name() == "xbel" && xml.attributes().value("version") == "1.0")
if (xml.name() == QLatin1String("xbel")
&& xml.attributes().value(versionAttribute()) == QLatin1String("1.0")) {
readXBEL();
else
} else {
xml.raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
}
}
return !xml.error();
@ -95,14 +97,14 @@ QString XbelReader::errorString() const
//! [3]
void XbelReader::readXBEL()
{
Q_ASSERT(xml.isStartElement() && xml.name() == "xbel");
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("xbel"));
while (xml.readNextStartElement()) {
if (xml.name() == "folder")
if (xml.name() == QLatin1String("folder"))
readFolder(0);
else if (xml.name() == "bookmark")
else if (xml.name() == QLatin1String("bookmark"))
readBookmark(0);
else if (xml.name() == "separator")
else if (xml.name() == QLatin1String("separator"))
readSeparator(0);
else
xml.skipCurrentElement();
@ -113,7 +115,7 @@ void XbelReader::readXBEL()
//! [4]
void XbelReader::readTitle(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "title");
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("title"));
QString title = xml.readElementText();
item->setText(0, title);
@ -123,7 +125,7 @@ void XbelReader::readTitle(QTreeWidgetItem *item)
//! [5]
void XbelReader::readSeparator(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "separator");
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("separator"));
QTreeWidgetItem *separator = createChildItem(item);
separator->setFlags(item->flags() & ~Qt::ItemIsSelectable);
@ -134,20 +136,20 @@ void XbelReader::readSeparator(QTreeWidgetItem *item)
void XbelReader::readFolder(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "folder");
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("folder"));
QTreeWidgetItem *folder = createChildItem(item);
bool folded = (xml.attributes().value("folded") != "no");
bool folded = (xml.attributes().value(foldedAttribute()) != QLatin1String("no"));
treeWidget->setItemExpanded(folder, !folded);
while (xml.readNextStartElement()) {
if (xml.name() == "title")
if (xml.name() == QLatin1String("title"))
readTitle(folder);
else if (xml.name() == "folder")
else if (xml.name() == QLatin1String("folder"))
readFolder(folder);
else if (xml.name() == "bookmark")
else if (xml.name() == QLatin1String("bookmark"))
readBookmark(folder);
else if (xml.name() == "separator")
else if (xml.name() == QLatin1String("separator"))
readSeparator(folder);
else
xml.skipCurrentElement();
@ -156,16 +158,16 @@ void XbelReader::readFolder(QTreeWidgetItem *item)
void XbelReader::readBookmark(QTreeWidgetItem *item)
{
Q_ASSERT(xml.isStartElement() && xml.name() == "bookmark");
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("bookmark"));
QTreeWidgetItem *bookmark = createChildItem(item);
bookmark->setFlags(bookmark->flags() | Qt::ItemIsEditable);
bookmark->setIcon(0, bookmarkIcon);
bookmark->setText(0, QObject::tr("Unknown title"));
bookmark->setText(1, xml.attributes().value("href").toString());
bookmark->setText(1, xml.attributes().value(hrefAttribute()).toString());
while (xml.readNextStartElement()) {
if (xml.name() == "title")
if (xml.name() == QLatin1String("title"))
readTitle(bookmark);
else
xml.skipCurrentElement();

View File

@ -71,6 +71,10 @@ public:
QString errorString() const;
static inline QString versionAttribute() { return QStringLiteral("version"); }
static inline QString hrefAttribute() { return QStringLiteral("href"); }
static inline QString foldedAttribute() { return QStringLiteral("folded"); }
private:
//! [2]
void readXBEL();

View File

@ -51,9 +51,14 @@
#include <QtWidgets>
#include "xbelwriter.h"
#include "xbelreader.h"
static inline QString yesValue() { return QStringLiteral("yes"); }
static inline QString noValue() { return QStringLiteral("no"); }
static inline QString titleElement() { return QStringLiteral("title"); }
//! [0]
XbelWriter::XbelWriter(QTreeWidget *treeWidget)
XbelWriter::XbelWriter(const QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
xml.setAutoFormatting(true);
@ -66,9 +71,9 @@ bool XbelWriter::writeFile(QIODevice *device)
xml.setDevice(device);
xml.writeStartDocument();
xml.writeDTD("<!DOCTYPE xbel>");
xml.writeStartElement("xbel");
xml.writeAttribute("version", "1.0");
xml.writeDTD(QStringLiteral("<!DOCTYPE xbel>"));
xml.writeStartElement(QStringLiteral("xbel"));
xml.writeAttribute(XbelReader::versionAttribute(), QStringLiteral("1.0"));
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
writeItem(treeWidget->topLevelItem(i));
@ -78,24 +83,24 @@ bool XbelWriter::writeFile(QIODevice *device)
//! [1]
//! [2]
void XbelWriter::writeItem(QTreeWidgetItem *item)
void XbelWriter::writeItem(const QTreeWidgetItem *item)
{
QString tagName = item->data(0, Qt::UserRole).toString();
if (tagName == "folder") {
if (tagName == QLatin1String("folder")) {
bool folded = !treeWidget->isItemExpanded(item);
xml.writeStartElement(tagName);
xml.writeAttribute("folded", folded ? "yes" : "no");
xml.writeTextElement("title", item->text(0));
xml.writeAttribute(XbelReader::foldedAttribute(), folded ? yesValue() : noValue());
xml.writeTextElement(titleElement(), item->text(0));
for (int i = 0; i < item->childCount(); ++i)
writeItem(item->child(i));
xml.writeEndElement();
} else if (tagName == "bookmark") {
} else if (tagName == QLatin1String("bookmark")) {
xml.writeStartElement(tagName);
if (!item->text(1).isEmpty())
xml.writeAttribute("href", item->text(1));
xml.writeTextElement("title", item->text(0));
xml.writeAttribute(XbelReader::hrefAttribute(), item->text(1));
xml.writeTextElement(titleElement(), item->text(0));
xml.writeEndElement();
} else if (tagName == "separator") {
} else if (tagName == QLatin1String("separator")) {
xml.writeEmptyElement(tagName);
}
}

View File

@ -62,13 +62,13 @@ QT_END_NAMESPACE
class XbelWriter
{
public:
XbelWriter(QTreeWidget *treeWidget);
explicit XbelWriter(const QTreeWidget *treeWidget);
bool writeFile(QIODevice *device);
private:
void writeItem(QTreeWidgetItem *item);
void writeItem(const QTreeWidgetItem *item);
QXmlStreamWriter xml;
QTreeWidget *treeWidget;
const QTreeWidget *treeWidget;
};
//! [0]