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:
parent
146f6d261b
commit
8d71fae080
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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("&", "&");
|
||||
result.replace("<", "<");
|
||||
result.replace(">", ">");
|
||||
result.replace('&', "&");
|
||||
result.replace('<', "<");
|
||||
result.replace('>', ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
QString XbelGenerator::escapedAttribute(const QString &str)
|
||||
{
|
||||
QString result = escapedText(str);
|
||||
result.replace("\"", """);
|
||||
result.replace(QLatin1Char('"'), """);
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user