1 //  -*- c-basic-offset:4; indent-tabs-mode:nil -*-
2 /*
3     This file is part of the KDE libraries
4     SPDX-FileCopyrightText: 2007 Daniel Teske <teske@squorn.de>
5 
6     SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kbookmarkdialog.h"
10 #include "kbookmarkdialog_p.h"
11 #include "kbookmarkmanager.h"
12 #include "kbookmarkmenu.h"
13 #include "kbookmarkmenu_p.h"
14 
15 #include <QDialogButtonBox>
16 #include <QFormLayout>
17 #include <QHeaderView>
18 #include <QIcon>
19 #include <QInputDialog>
20 #include <QLabel>
21 #include <QLineEdit>
22 #include <QPushButton>
23 #include <QTreeWidget>
24 
25 #include <KGuiItem>
26 
KBookmarkDialogPrivate(KBookmarkDialog * qq)27 KBookmarkDialogPrivate::KBookmarkDialogPrivate(KBookmarkDialog *qq)
28     : q(qq)
29     , folderTree(nullptr)
30     , layout(false)
31 {
32 }
33 
~KBookmarkDialogPrivate()34 KBookmarkDialogPrivate::~KBookmarkDialogPrivate()
35 {
36 }
37 
initLayout()38 void KBookmarkDialogPrivate::initLayout()
39 {
40     QBoxLayout *vbox = new QVBoxLayout(q);
41 
42     QFormLayout *form = new QFormLayout();
43     vbox->addLayout(form);
44 
45     form->addRow(titleLabel, title);
46     form->addRow(urlLabel, url);
47     form->addRow(commentLabel, comment);
48 
49     vbox->addWidget(folderTree);
50     vbox->addWidget(buttonBox);
51 }
52 
initLayoutPrivate()53 void KBookmarkDialogPrivate::initLayoutPrivate()
54 {
55     title = new QLineEdit(q);
56     title->setMinimumWidth(300);
57     titleLabel = new QLabel(KBookmarkDialog::tr("Name:", "@label:textbox"), q);
58     titleLabel->setBuddy(title);
59 
60     url = new QLineEdit(q);
61     url->setMinimumWidth(300);
62     urlLabel = new QLabel(KBookmarkDialog::tr("Location:", "@label:textbox"), q);
63     urlLabel->setBuddy(url);
64 
65     comment = new QLineEdit(q);
66     comment->setMinimumWidth(300);
67     commentLabel = new QLabel(KBookmarkDialog::tr("Comment:", "@label:textbox"), q);
68     commentLabel->setBuddy(comment);
69 
70     folderTree = new QTreeWidget(q);
71     folderTree->setColumnCount(1);
72     folderTree->header()->hide();
73     folderTree->setSortingEnabled(false);
74     folderTree->setSelectionMode(QTreeWidget::SingleSelection);
75     folderTree->setSelectionBehavior(QTreeWidget::SelectRows);
76     folderTree->setMinimumSize(60, 100);
77     QTreeWidgetItem *root = new KBookmarkTreeItem(folderTree);
78     fillGroup(root, mgr->root());
79 
80     buttonBox = new QDialogButtonBox(q);
81     buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
82     q->connect(buttonBox, &QDialogButtonBox::accepted, q, &KBookmarkDialog::accept);
83     q->connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
84 
85     initLayout();
86     layout = true;
87 }
88 
fillGroup(QTreeWidgetItem * parentItem,const KBookmarkGroup & group,const KBookmarkGroup & selectGroup)89 void KBookmarkDialogPrivate::fillGroup(QTreeWidgetItem *parentItem, const KBookmarkGroup &group, const KBookmarkGroup &selectGroup)
90 {
91     for (KBookmark bk = group.first(); !bk.isNull(); bk = group.next(bk)) {
92         if (bk.isGroup()) {
93             const KBookmarkGroup bkGroup = bk.toGroup();
94             QTreeWidgetItem *item = new KBookmarkTreeItem(parentItem, folderTree, bkGroup);
95             if (selectGroup == bkGroup) {
96                 folderTree->setCurrentItem(item);
97             }
98             fillGroup(item, bkGroup, selectGroup);
99         }
100     }
101 }
102 
setParentBookmark(const KBookmark & bm)103 void KBookmarkDialogPrivate::setParentBookmark(const KBookmark &bm)
104 {
105     QString address = bm.address();
106     KBookmarkTreeItem *item = static_cast<KBookmarkTreeItem *>(folderTree->topLevelItem(0));
107     while (true) {
108         if (item->address() == bm.address()) {
109             folderTree->setCurrentItem(item);
110             return;
111         }
112         for (int i = 0; i < item->childCount(); ++i) {
113             KBookmarkTreeItem *child = static_cast<KBookmarkTreeItem *>(item->child(i));
114             if (KBookmark::commonParent(child->address(), address) == child->address()) {
115                 item = child;
116                 break;
117             }
118         }
119     }
120 }
121 
parentBookmark()122 KBookmarkGroup KBookmarkDialogPrivate::parentBookmark()
123 {
124     KBookmarkTreeItem *item = dynamic_cast<KBookmarkTreeItem *>(folderTree->currentItem());
125     if (!item) {
126         return mgr->root();
127     }
128     const QString &address = item->address();
129     return mgr->findByAddress(address).toGroup();
130 }
131 
accept()132 void KBookmarkDialog::accept()
133 {
134     if (d->mode == KBookmarkDialogPrivate::NewFolder) {
135         KBookmarkGroup parent = d->parentBookmark();
136         if (d->title->text().isEmpty()) {
137             d->title->setText(QStringLiteral("New Folder"));
138         }
139         d->bm = parent.createNewFolder(d->title->text());
140         d->bm.setDescription(d->comment->text());
141         d->mgr->emitChanged(parent);
142     } else if (d->mode == KBookmarkDialogPrivate::NewBookmark) {
143         KBookmarkGroup parent = d->parentBookmark();
144         if (d->title->text().isEmpty()) {
145             d->title->setText(QStringLiteral("New Bookmark"));
146         }
147         d->bm = parent.addBookmark(d->title->text(), QUrl(d->url->text()), d->icon);
148         d->bm.setDescription(d->comment->text());
149         d->mgr->emitChanged(parent);
150     } else if (d->mode == KBookmarkDialogPrivate::NewMultipleBookmarks) {
151         KBookmarkGroup parent = d->parentBookmark();
152         if (d->title->text().isEmpty()) {
153             d->title->setText(QStringLiteral("New Folder"));
154         }
155         d->bm = parent.createNewFolder(d->title->text());
156         d->bm.setDescription(d->comment->text());
157         for (const KBookmarkOwner::FutureBookmark &fb : std::as_const(d->list)) {
158             d->bm.toGroup().addBookmark(fb.title(), fb.url(), fb.icon());
159         }
160         d->mgr->emitChanged(parent);
161     } else if (d->mode == KBookmarkDialogPrivate::EditBookmark) {
162         d->bm.setFullText(d->title->text());
163         d->bm.setUrl(QUrl(d->url->text()));
164         d->bm.setDescription(d->comment->text());
165         d->mgr->emitChanged(d->bm.parentGroup());
166     } else if (d->mode == d->SelectFolder) {
167         d->bm = d->parentBookmark();
168     }
169     QDialog::accept();
170 }
171 
editBookmark(const KBookmark & bm)172 KBookmark KBookmarkDialog::editBookmark(const KBookmark &bm)
173 {
174     if (!d->layout) {
175         d->initLayoutPrivate();
176     }
177 
178     KGuiItem::assign(d->buttonBox->button(QDialogButtonBox::Ok), KGuiItem(tr("Update", "@action:button")));
179     setWindowTitle(tr("Bookmark Properties", "@title:window"));
180     d->url->setVisible(!bm.isGroup());
181     d->urlLabel->setVisible(!bm.isGroup());
182     d->bm = bm;
183     d->title->setText(bm.fullText());
184     d->url->setText(bm.url().toString());
185     d->comment->setVisible(true);
186     d->commentLabel->setVisible(true);
187     d->comment->setText(bm.description());
188     d->folderTree->setVisible(false);
189 
190     d->mode = KBookmarkDialogPrivate::EditBookmark;
191 
192     if (exec() == QDialog::Accepted) {
193         return d->bm;
194     } else {
195         return KBookmark();
196     }
197 }
198 
addBookmark(const QString & title,const QUrl & url,const QString & icon,KBookmark parent)199 KBookmark KBookmarkDialog::addBookmark(const QString &title, const QUrl &url, const QString &icon, KBookmark parent)
200 {
201     if (!d->layout) {
202         d->initLayoutPrivate();
203     }
204     if (parent.isNull()) {
205         parent = d->mgr->root();
206     }
207 
208     QPushButton *newButton = new QPushButton;
209     KGuiItem::assign(newButton, KGuiItem(tr("&New Folder...", "@action:button"), QStringLiteral("folder-new")));
210     d->buttonBox->addButton(newButton, QDialogButtonBox::ActionRole);
211     connect(newButton, &QAbstractButton::clicked, this, &KBookmarkDialog::newFolderButton);
212 
213     KGuiItem::assign(d->buttonBox->button(QDialogButtonBox::Ok), KGuiItem(tr("Add", "@action:button"), QStringLiteral("bookmark-new")));
214     setWindowTitle(tr("Add Bookmark", "@title:window"));
215     d->url->setVisible(true);
216     d->urlLabel->setVisible(true);
217     d->title->setText(title);
218     d->url->setText(url.toString());
219     d->comment->setText(QString());
220     d->comment->setVisible(true);
221     d->commentLabel->setVisible(true);
222     d->setParentBookmark(parent);
223     d->folderTree->setVisible(true);
224     d->icon = icon;
225 
226     d->mode = KBookmarkDialogPrivate::NewBookmark;
227 
228     if (exec() == QDialog::Accepted) {
229         return d->bm;
230     } else {
231         return KBookmark();
232     }
233 }
234 
addBookmarks(const QList<KBookmarkOwner::FutureBookmark> & list,const QString & name,KBookmarkGroup parent)235 KBookmarkGroup KBookmarkDialog::addBookmarks(const QList<KBookmarkOwner::FutureBookmark> &list, const QString &name, KBookmarkGroup parent)
236 {
237     if (!d->layout) {
238         d->initLayoutPrivate();
239     }
240     if (parent.isNull()) {
241         parent = d->mgr->root();
242     }
243 
244     d->list = list;
245 
246     QPushButton *newButton = new QPushButton;
247     KGuiItem::assign(newButton, KGuiItem(tr("&New Folder...", "@action:button"), QStringLiteral("folder-new")));
248     d->buttonBox->addButton(newButton, QDialogButtonBox::ActionRole);
249     connect(newButton, &QAbstractButton::clicked, this, &KBookmarkDialog::newFolderButton);
250 
251     KGuiItem::assign(d->buttonBox->button(QDialogButtonBox::Ok), KGuiItem(tr("Add", "@action:button"), QStringLiteral("bookmark-new")));
252     setWindowTitle(tr("Add Bookmarks", "@title:window"));
253     d->url->setVisible(false);
254     d->urlLabel->setVisible(false);
255     d->title->setText(name);
256     d->comment->setVisible(true);
257     d->commentLabel->setVisible(true);
258     d->comment->setText(QString());
259     d->setParentBookmark(parent);
260     d->folderTree->setVisible(true);
261 
262     d->mode = KBookmarkDialogPrivate::NewMultipleBookmarks;
263 
264     if (exec() == QDialog::Accepted) {
265         return d->bm.toGroup();
266     } else {
267         return KBookmarkGroup();
268     }
269 }
270 
selectFolder(KBookmark parent)271 KBookmarkGroup KBookmarkDialog::selectFolder(KBookmark parent)
272 {
273     if (!d->layout) {
274         d->initLayoutPrivate();
275     }
276     if (parent.isNull()) {
277         parent = d->mgr->root();
278     }
279 
280     QPushButton *newButton = new QPushButton;
281     KGuiItem::assign(newButton, KGuiItem(tr("&New Folder...", "@action:button"), QStringLiteral("folder-new")));
282     d->buttonBox->addButton(newButton, QDialogButtonBox::ActionRole);
283     connect(newButton, &QAbstractButton::clicked, this, &KBookmarkDialog::newFolderButton);
284 
285     setWindowTitle(tr("Select Folder", "@title:window"));
286     d->url->setVisible(false);
287     d->urlLabel->setVisible(false);
288     d->title->setVisible(false);
289     d->titleLabel->setVisible(false);
290     d->comment->setVisible(false);
291     d->commentLabel->setVisible(false);
292     d->setParentBookmark(parent);
293     d->folderTree->setVisible(true);
294 
295     d->mode = d->SelectFolder;
296 
297     if (exec() == QDialog::Accepted) {
298         return d->bm.toGroup();
299     } else {
300         return KBookmarkGroup();
301     }
302 }
303 
createNewFolder(const QString & name,KBookmark parent)304 KBookmarkGroup KBookmarkDialog::createNewFolder(const QString &name, KBookmark parent)
305 {
306     if (!d->layout) {
307         d->initLayoutPrivate();
308     }
309     if (parent.isNull()) {
310         parent = d->mgr->root();
311     }
312 
313     setWindowTitle(tr("New Folder", "@title:window"));
314     d->url->setVisible(false);
315     d->urlLabel->setVisible(false);
316     d->comment->setVisible(true);
317     d->commentLabel->setVisible(true);
318     d->comment->setText(QString());
319     d->title->setText(name);
320     d->setParentBookmark(parent);
321     d->folderTree->setVisible(true);
322 
323     d->mode = KBookmarkDialogPrivate::NewFolder;
324 
325     if (exec() == QDialog::Accepted) {
326         return d->bm.toGroup();
327     } else {
328         return KBookmarkGroup();
329     }
330 }
331 
KBookmarkDialog(KBookmarkManager * mgr,QWidget * parent)332 KBookmarkDialog::KBookmarkDialog(KBookmarkManager *mgr, QWidget *parent)
333     : QDialog(parent)
334     , d(new KBookmarkDialogPrivate(this))
335 {
336     d->mgr = mgr;
337 }
338 
339 KBookmarkDialog::~KBookmarkDialog() = default;
340 
newFolderButton()341 void KBookmarkDialog::newFolderButton()
342 {
343     QString caption = d->parentBookmark().fullText().isEmpty() ? tr("Create New Bookmark Folder", "@title:window")
344                                                                : tr("Create New Bookmark Folder in %1", "@title:window").arg(d->parentBookmark().text());
345     bool ok;
346     QString text = QInputDialog::getText(this, caption, tr("New folder:", "@label:textbox"), QLineEdit::Normal, QString(), &ok);
347     if (!ok) {
348         return;
349     }
350 
351     KBookmarkGroup group = d->parentBookmark().createNewFolder(text);
352     if (!group.isNull()) {
353         KBookmarkGroup parentGroup = group.parentGroup();
354         d->mgr->emitChanged(parentGroup);
355         d->folderTree->clear();
356         QTreeWidgetItem *root = new KBookmarkTreeItem(d->folderTree);
357         d->fillGroup(root, d->mgr->root(), group);
358     }
359 }
360 
361 /********************************************************************/
362 
KBookmarkTreeItem(QTreeWidget * tree)363 KBookmarkTreeItem::KBookmarkTreeItem(QTreeWidget *tree)
364     : QTreeWidgetItem(tree)
365     , m_address(QLatin1String(""))
366 {
367     setText(0, KBookmarkDialog::tr("Bookmarks", "name of the container of all browser bookmarks"));
368     setIcon(0, QIcon::fromTheme(QStringLiteral("bookmarks")));
369     tree->expandItem(this);
370     tree->setCurrentItem(this);
371     setSelected(true);
372 }
373 
KBookmarkTreeItem(QTreeWidgetItem * parent,QTreeWidget * tree,const KBookmarkGroup & bk)374 KBookmarkTreeItem::KBookmarkTreeItem(QTreeWidgetItem *parent, QTreeWidget *tree, const KBookmarkGroup &bk)
375     : QTreeWidgetItem(parent)
376 {
377     setIcon(0, QIcon::fromTheme(bk.icon()));
378     setText(0, bk.fullText());
379     tree->expandItem(this);
380     m_address = bk.address();
381 }
382 
~KBookmarkTreeItem()383 KBookmarkTreeItem::~KBookmarkTreeItem()
384 {
385 }
386 
address()387 QString KBookmarkTreeItem::address()
388 {
389     return m_address;
390 }
391