Changeset View
Changeset View
Standalone View
Standalone View
krusader/BookMan/krbookmarkhandler.cpp
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Line(s) | |||||
47 | 47 | | |||
48 | #define SPECIAL_BOOKMARKS true | 48 | #define SPECIAL_BOOKMARKS true | ||
49 | 49 | | |||
50 | // ------------------------ for internal use | 50 | // ------------------------ for internal use | ||
51 | #define BOOKMARKS_FILE "krusader/krbookmarks.xml" | 51 | #define BOOKMARKS_FILE "krusader/krbookmarks.xml" | ||
52 | #define CONNECT_BM(X) { disconnect(X, SIGNAL(activated(QUrl)), 0, 0); connect(X, SIGNAL(activated(QUrl)), this, SLOT(slotActivated(QUrl))); } | 52 | #define CONNECT_BM(X) { disconnect(X, SIGNAL(activated(QUrl)), 0, 0); connect(X, SIGNAL(activated(QUrl)), this, SLOT(slotActivated(QUrl))); } | ||
53 | 53 | | |||
54 | KrBookmarkHandler::KrBookmarkHandler(KrMainWindow *mainWindow) : QObject(mainWindow->widget()), | 54 | KrBookmarkHandler::KrBookmarkHandler(KrMainWindow *mainWindow) : QObject(mainWindow->widget()), | ||
55 | _mainWindow(mainWindow), _middleClick(false), _mainBookmarkPopup(0), _specialBookmarks() | 55 | _mainWindow(mainWindow), _middleClick(false), _mainBookmarkPopup(0), _specialBookmarks(), | ||
56 | _quickSearchAction(0) | ||||
56 | { | 57 | { | ||
57 | // create our own action collection and make the shortcuts apply only to parent | 58 | // create our own action collection and make the shortcuts apply only to parent | ||
58 | _privateCollection = new KActionCollection(this); | 59 | _privateCollection = new KActionCollection(this); | ||
59 | _collection = _mainWindow->actions(); | 60 | _collection = _mainWindow->actions(); | ||
60 | 61 | | |||
61 | // create _root: father of all bookmarks. it is a dummy bookmark and never shown | 62 | // create _root: father of all bookmarks. it is a dummy bookmark and never shown | ||
62 | _root = new KrBookmark(i18n("Bookmarks")); | 63 | _root = new KrBookmark(i18n("Bookmarks")); | ||
63 | _root->setParent(this); | 64 | _root->setParent(this); | ||
64 | 65 | | |||
65 | // load bookmarks | 66 | // load bookmarks | ||
66 | importFromFile(); | 67 | importFromFile(); | ||
67 | 68 | | |||
68 | // hack | 69 | // create bookmark manager | ||
69 | QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + BOOKMARKS_FILE; | 70 | QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + BOOKMARKS_FILE; | ||
70 | manager = KBookmarkManager::managerForFile(filename, QStringLiteral("krusader")); | 71 | manager = KBookmarkManager::managerForFile(filename, QStringLiteral("krusader")); | ||
71 | connect(manager, SIGNAL(changed(QString,QString)), this, SLOT(bookmarksChanged(QString,QString))); | 72 | connect(manager, SIGNAL(changed(QString,QString)), this, SLOT(bookmarksChanged(QString,QString))); | ||
73 | | ||||
74 | // create the quick search bar and action | ||||
75 | _quickSearchAction = new QWidgetAction(nullptr); | ||||
76 | _quickSearchBar = new QLineEdit(); | ||||
martinkostolny: I'd prefer:
```_quickSearchAction = new QWidgetAction(this);
_quickSearchBar = new QLineEdit… | |||||
Thanks! I was moving around the code and forgot to update the ownership. QLineEdit doesn't need the widget because the next call transfers ownership to the action. https://doc.qt.io/qt-5/qwidgetaction.html#setDefaultWidget nmel: Thanks! I was moving around the code and forgot to update the ownership. QLineEdit doesn't need… | |||||
77 | _quickSearchAction->setDefaultWidget(_quickSearchBar); | ||||
78 | _quickSearchAction->setEnabled(false); | ||||
79 | _quickSearchAction->setVisible(false); | ||||
80 | | ||||
81 | // fill a dummy menu to properly init actions (allows toolbar bookmark buttons to work properly) | ||||
82 | auto menu = new QMenu(mainWindow->widget()); | ||||
83 | populate(menu); | ||||
84 | menu->deleteLater(); | ||||
72 | } | 85 | } | ||
73 | 86 | | |||
74 | KrBookmarkHandler::~KrBookmarkHandler() | 87 | KrBookmarkHandler::~KrBookmarkHandler() | ||
75 | { | 88 | { | ||
76 | delete manager; | 89 | delete manager; | ||
77 | delete _privateCollection; | 90 | delete _privateCollection; | ||
78 | } | 91 | } | ||
79 | 92 | | |||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Line(s) | |||||
302 | 315 | | |||
303 | BM_ERROR: | 316 | BM_ERROR: | ||
304 | KMessageBox::error(_mainWindow->widget(), i18n("Error reading bookmarks file: %1", errorMsg), i18n("Error")); | 317 | KMessageBox::error(_mainWindow->widget(), i18n("Error reading bookmarks file: %1", errorMsg), i18n("Error")); | ||
305 | 318 | | |||
306 | BM_SUCCESS: | 319 | BM_SUCCESS: | ||
307 | file.close(); | 320 | file.close(); | ||
308 | } | 321 | } | ||
309 | 322 | | |||
323 | void KrBookmarkHandler::_setQuickSearchText(const QString &text) | ||||
324 | { | ||||
325 | _quickSearchBar->setText(text); | ||||
326 | | ||||
327 | auto length = text.length(); | ||||
328 | _quickSearchAction->setVisible(length > 0); | ||||
329 | _quickSearchBar->setVisible(length > 0); | ||||
330 | if (length == 0) { | ||||
331 | resetShortcuts(); | ||||
332 | } | ||||
333 | } | ||||
334 | | ||||
335 | QString KrBookmarkHandler::_quickSearchText() const | ||||
336 | { | ||||
337 | return _quickSearchBar->text(); | ||||
338 | } | ||||
339 | | ||||
310 | void KrBookmarkHandler::populate(QMenu *menu) | 340 | void KrBookmarkHandler::populate(QMenu *menu) | ||
311 | { | 341 | { | ||
312 | _mainBookmarkPopup = menu; | 342 | _mainBookmarkPopup = menu; | ||
313 | menu->clear(); | 343 | menu->clear(); | ||
314 | _specialBookmarks.clear(); | 344 | _specialBookmarks.clear(); | ||
315 | buildMenu(_root, menu); | 345 | buildMenu(_root, menu); | ||
316 | } | 346 | } | ||
317 | 347 | | |||
318 | void KrBookmarkHandler::buildMenu(KrBookmark *parent, QMenu *menu) | 348 | void KrBookmarkHandler::buildMenu(KrBookmark *parent, QMenu *menu, int depth) | ||
319 | { | 349 | { | ||
320 | static int inSecondaryMenu = 0; // used to know if we're on the top menu | 350 | // add search bar widget to the top of the menu | ||
351 | if (depth == 0) { | ||||
352 | menu->addAction(_quickSearchAction); | ||||
353 | } | ||||
321 | 354 | | |||
322 | // run the loop twice, in order to put the folders on top. stupid but easy :-) | 355 | // run the loop twice, in order to put the folders on top. stupid but easy :-) | ||
323 | // note: this code drops the separators put there by the user | 356 | // note: this code drops the separators put there by the user | ||
324 | QListIterator<KrBookmark *> it(parent->children()); | 357 | QListIterator<KrBookmark *> it(parent->children()); | ||
325 | while (it.hasNext()) { | 358 | while (it.hasNext()) { | ||
326 | KrBookmark *bm = it.next(); | 359 | KrBookmark *bm = it.next(); | ||
327 | 360 | | |||
328 | if (!bm->isFolder()) continue; | 361 | if (!bm->isFolder()) continue; | ||
329 | QMenu *newMenu = new QMenu(menu); | 362 | QMenu *newMenu = new QMenu(menu); | ||
330 | newMenu->setIcon(QIcon(krLoader->loadIcon(bm->iconName(), KIconLoader::Small))); | 363 | newMenu->setIcon(QIcon(krLoader->loadIcon(bm->iconName(), KIconLoader::Small))); | ||
331 | newMenu->setTitle(bm->text()); | 364 | newMenu->setTitle(bm->text()); | ||
332 | QAction *menuAction = menu->addMenu(newMenu); | 365 | QAction *menuAction = menu->addMenu(newMenu); | ||
333 | QVariant v; | 366 | QVariant v; | ||
334 | v.setValue<KrBookmark *>(bm); | 367 | v.setValue<KrBookmark *>(bm); | ||
335 | menuAction->setData(v); | 368 | menuAction->setData(v); | ||
336 | 369 | | |||
337 | ++inSecondaryMenu; | 370 | buildMenu(bm, newMenu, depth + 1); | ||
338 | buildMenu(bm, newMenu); | | |||
339 | --inSecondaryMenu; | | |||
340 | } | 371 | } | ||
341 | 372 | | |||
342 | it.toFront(); | 373 | it.toFront(); | ||
343 | while (it.hasNext()) { | 374 | while (it.hasNext()) { | ||
344 | KrBookmark *bm = it.next(); | 375 | KrBookmark *bm = it.next(); | ||
345 | if (bm->isFolder()) continue; | 376 | if (bm->isFolder()) continue; | ||
346 | if (bm->isSeparator()) { | 377 | if (bm->isSeparator()) { | ||
347 | menu->addSeparator(); | 378 | menu->addSeparator(); | ||
348 | continue; | 379 | continue; | ||
349 | } | 380 | } | ||
350 | menu->addAction(bm); | 381 | menu->addAction(bm); | ||
351 | CONNECT_BM(bm); | 382 | CONNECT_BM(bm); | ||
352 | } | 383 | } | ||
353 | 384 | | |||
354 | if (!inSecondaryMenu) { | 385 | if (depth == 0) { | ||
355 | KConfigGroup group(krConfig, "Private"); | 386 | KConfigGroup group(krConfig, "Private"); | ||
356 | bool hasPopularURLs = group.readEntry("BM Popular URLs", true); | 387 | bool hasPopularURLs = group.readEntry("BM Popular URLs", true); | ||
357 | bool hasTrash = group.readEntry("BM Trash", true); | 388 | bool hasTrash = group.readEntry("BM Trash", true); | ||
358 | bool hasLan = group.readEntry("BM Lan", true); | 389 | bool hasLan = group.readEntry("BM Lan", true); | ||
359 | bool hasVirtualFS = group.readEntry("BM Virtual FS", true); | 390 | bool hasVirtualFS = group.readEntry("BM Virtual FS", true); | ||
360 | bool hasJumpback = group.readEntry("BM Jumpback", true); | 391 | bool hasJumpback = group.readEntry("BM Jumpback", true); | ||
361 | 392 | | |||
362 | if (hasPopularURLs) { | 393 | if (hasPopularURLs) { | ||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Line(s) | 446 | if (hasVirtualFS) { | |||
417 | menu->addAction(bm); | 448 | menu->addAction(bm); | ||
418 | _specialBookmarks.append(bm); | 449 | _specialBookmarks.append(bm); | ||
419 | CONNECT_BM(bm); | 450 | CONNECT_BM(bm); | ||
420 | } | 451 | } | ||
421 | 452 | | |||
422 | if (hasJumpback) { | 453 | if (hasJumpback) { | ||
423 | // add the jump-back button | 454 | // add the jump-back button | ||
424 | ListPanelActions *actions = _mainWindow->listPanelActions(); | 455 | ListPanelActions *actions = _mainWindow->listPanelActions(); | ||
456 | if (actions) { | ||||
425 | menu->addAction(actions->actJumpBack); | 457 | menu->addAction(actions->actJumpBack); | ||
426 | _specialBookmarks.append(actions->actJumpBack); | 458 | _specialBookmarks.append(actions->actJumpBack); | ||
427 | menu->addSeparator(); | 459 | menu->addSeparator(); | ||
428 | menu->addAction(actions->actSetJumpBack); | 460 | menu->addAction(actions->actSetJumpBack); | ||
429 | _specialBookmarks.append(actions->actSetJumpBack); | 461 | _specialBookmarks.append(actions->actSetJumpBack); | ||
430 | } | 462 | } | ||
431 | } | 463 | } | ||
464 | } | ||||
432 | 465 | | |||
433 | if (!hasJumpback) | 466 | if (!hasJumpback) | ||
434 | menu->addSeparator(); | 467 | menu->addSeparator(); | ||
435 | 468 | | |||
436 | menu->addAction(KrActions::actAddBookmark); | 469 | menu->addAction(KrActions::actAddBookmark); | ||
437 | _specialBookmarks.append(KrActions::actAddBookmark); | 470 | _specialBookmarks.append(KrActions::actAddBookmark); | ||
438 | QAction *bmAct = menu->addAction(krLoader->loadIcon("bookmarks", KIconLoader::Small), | 471 | QAction *bmAct = menu->addAction(krLoader->loadIcon("bookmarks", KIconLoader::Small), | ||
439 | i18n("Manage Bookmarks"), manager, SLOT(slotEditBookmarks())); | 472 | i18n("Manage Bookmarks"), manager, SLOT(slotEditBookmarks())); | ||
Show All 28 Lines | |||||
468 | { | 501 | { | ||
469 | importFromFile(); | 502 | importFromFile(); | ||
470 | } | 503 | } | ||
471 | 504 | | |||
472 | bool KrBookmarkHandler::eventFilter(QObject *obj, QEvent *ev) | 505 | bool KrBookmarkHandler::eventFilter(QObject *obj, QEvent *ev) | ||
473 | { | 506 | { | ||
474 | if (obj->inherits("QMenu") && (ev->type() == QEvent::Show || | 507 | if (obj->inherits("QMenu") && (ev->type() == QEvent::Show || | ||
475 | ev->type() == QEvent::Close)) { | 508 | ev->type() == QEvent::Close)) { | ||
476 | _menuSearch = ""; | 509 | _setQuickSearchText(""); | ||
477 | resetShortcuts(); | | |||
478 | } | 510 | } | ||
479 | 511 | | |||
480 | // Having it occur on keypress is consistent with other shortcuts, | 512 | // Having it occur on keypress is consistent with other shortcuts, | ||
481 | // such as ctrl+w and the '&' bookmark shortcut standard | 513 | // such as ctrl+w and the '&' bookmark shortcut standard | ||
482 | // (&movies makes m a shortcut for said bookmark) | 514 | // (&movies makes m a shortcut for said bookmark) | ||
483 | if (ev->type() == QEvent::KeyPress && obj->inherits("QMenu")) { | 515 | if (ev->type() == QEvent::KeyPress && obj->inherits("QMenu")) { | ||
484 | QKeyEvent *kev = static_cast<QKeyEvent *>(ev); | 516 | QKeyEvent *kev = static_cast<QKeyEvent *>(ev); | ||
485 | QMenu *menu = static_cast<QMenu *>(obj); | 517 | QMenu *menu = static_cast<QMenu *>(obj); | ||
486 | QList<QAction *> acts = menu->actions(); | 518 | QList<QAction *> acts = menu->actions(); | ||
487 | 519 | | |||
488 | if (kev->modifiers() != Qt::NoModifier || | 520 | if (kev->modifiers() != Qt::NoModifier || | ||
489 | kev->text().isEmpty() || | 521 | kev->text().isEmpty() || | ||
490 | kev->key() == Qt::Key_Delete) { | 522 | kev->key() == Qt::Key_Delete) { | ||
491 | return QObject::eventFilter(obj, ev); | 523 | return QObject::eventFilter(obj, ev); | ||
492 | } | 524 | } | ||
493 | 525 | | |||
494 | if (kev->key() == Qt::Key_Backspace) { | 526 | if (kev->key() == Qt::Key_Backspace) { | ||
495 | _menuSearch.chop(1); | 527 | auto newSearchText = _quickSearchText(); | ||
496 | if (_menuSearch.length() == 0) { | 528 | newSearchText.chop(1); | ||
497 | resetShortcuts(); | 529 | _setQuickSearchText(newSearchText); | ||
530 | | ||||
531 | if (_quickSearchText().length() == 0) { | ||||
498 | return QObject::eventFilter(obj, ev); | 532 | return QObject::eventFilter(obj, ev); | ||
499 | } | 533 | } | ||
500 | } else { | 534 | } else { | ||
501 | _menuSearch.append(kev->text()); | 535 | _setQuickSearchText(_quickSearchText().append(kev->text())); | ||
502 | } | 536 | } | ||
503 | 537 | | |||
504 | QAction* found = nullptr; | 538 | QAction* found = nullptr; | ||
505 | const int menuSearchLength = _menuSearch.length(); | 539 | const int quickSearchTextLength = _quickSearchText().length(); | ||
506 | bool solematch; | 540 | bool solematch; | ||
507 | for (auto act : acts) { | 541 | for (auto act : acts) { | ||
508 | if (act->isSeparator() || act->text() == "") { | 542 | if (act->isSeparator() || act->text() == "") { | ||
509 | continue; | 543 | continue; | ||
510 | } | 544 | } | ||
511 | 545 | | |||
512 | if (menuSearchLength == 1 && kev->key() != Qt::Key_Backspace && !kev->text().isEmpty()) { | 546 | if (quickSearchTextLength == 1 && kev->key() != Qt::Key_Backspace && !kev->text().isEmpty()) { | ||
513 | if (act->text().contains('&' + kev->text(), Qt::CaseInsensitive)) { | 547 | if (act->text().contains('&' + kev->text(), Qt::CaseInsensitive)) { | ||
514 | _menuSearch = ""; | 548 | _setQuickSearchText(""); | ||
515 | resetShortcuts(); | | |||
516 | break; | 549 | break; | ||
517 | } | 550 | } | ||
518 | 551 | | |||
519 | _msNamesWithAccelerators.insert(act, act->text()); | 552 | _msNamesWithAccelerators.insert(act, act->text()); | ||
520 | } | 553 | } | ||
521 | 554 | | |||
522 | act->setText(KLocalizedString::removeAcceleratorMarker(act->text())); | 555 | act->setText(KLocalizedString::removeAcceleratorMarker(act->text())); | ||
523 | if (act->text().left(menuSearchLength).compare(_menuSearch, Qt::CaseInsensitive) == 0) { | 556 | if (act->text().left(quickSearchTextLength).compare(_quickSearchText(), Qt::CaseInsensitive) == 0) { | ||
524 | act->setText(createShortcutUnderline(act->text(), menuSearchLength)); | 557 | act->setText(createShortcutUnderline(act->text(), quickSearchTextLength)); | ||
525 | if (!found) { | 558 | if (!found) { | ||
526 | found = act; | 559 | found = act; | ||
527 | solematch = true; | 560 | solematch = true; | ||
528 | } else { | 561 | } else { | ||
529 | solematch = false; | 562 | solematch = false; | ||
530 | } | 563 | } | ||
531 | } | 564 | } | ||
532 | } | 565 | } | ||
533 | 566 | | |||
534 | if (found && solematch) { | 567 | if (found && solematch) { | ||
535 | if ((bool) found->menu()) { | 568 | if ((bool) found->menu()) { | ||
536 | menu->setActiveAction(found); | 569 | menu->setActiveAction(found); | ||
537 | } else { | 570 | } else { | ||
538 | found->activate(QAction::Trigger); | 571 | found->activate(QAction::Trigger); | ||
539 | } | 572 | } | ||
540 | _menuSearch = ""; | 573 | _setQuickSearchText(""); | ||
541 | resetShortcuts(); | 574 | } else if (found && quickSearchTextLength > 1) { | ||
542 | } else if (found && menuSearchLength > 1) { | | |||
543 | // & bookmark code will give focus as long as there is only one | 575 | // & bookmark code will give focus as long as there is only one | ||
544 | // & character | 576 | // & character | ||
545 | menu->setActiveAction(found); | 577 | menu->setActiveAction(found); | ||
546 | } else if (!found) { | | |||
547 | _menuSearch = ""; | | |||
548 | resetShortcuts(); | | |||
549 | } | 578 | } | ||
550 | } | 579 | } | ||
551 | 580 | | |||
552 | if (ev->type() == QEvent::MouseButtonRelease) { | 581 | if (ev->type() == QEvent::MouseButtonRelease) { | ||
553 | switch (static_cast<QMouseEvent *>(ev)->button()) { | 582 | switch (static_cast<QMouseEvent *>(ev)->button()) { | ||
554 | case Qt::RightButton: | 583 | case Qt::RightButton: | ||
555 | _middleClick = false; | 584 | _middleClick = false; | ||
556 | if (obj->inherits("QMenu")) { | 585 | if (obj->inherits("QMenu")) { | ||
▲ Show 20 Lines • Show All 196 Lines • Show Last 20 Lines |
I'd prefer:
...this way the objects will be automatically destroyed when parent is destroyed. But I may be wrong.