15#include <QApplication>
18#include <QDragLeaveEvent>
19#include <QDragMoveEvent>
29#include "../../backend/btbookmarksmodel.h"
30#include "../../backend/config/btconfig.h"
31#include "../../backend/drivers/cswordmoduleinfo.h"
32#include "../../backend/managers/cswordbackend.h"
33#include "../../util/btassert.h"
34#include "../../util/btconnect.h"
35#include "../../util/bticons.h"
36#include "../../util/cresmgr.h"
37#include "../../util/tool.h"
38#include "../bookmarks/bteditbookmarkdialog.h"
39#include "../bookmarks/cbookmarkindex.h"
40#include "../btprinter.h"
41#include "../BtMimeData.h"
42#include "../messagedialog.h"
48 return QStringLiteral(
"%1 (*.btb);;%2 (*)")
49 .arg(QObject::tr(
"BibleTime bookmark files"),
50 QObject::tr(
"All files"));
58 , m_bookmarksModel{nullptr}
60 setMouseTracking(
true);
63 btConfig().value<int>(QStringLiteral(
"GUI/magDelay"), 400));
64 setContextMenuPolicy(Qt::CustomContextMenu);
65 setHeaderHidden(
true);
70 setHeaderHidden(
true);
72 setFocusPolicy(Qt::WheelFocus);
77 setDragDropMode(QAbstractItemView::DragDrop);
78 viewport()->setAcceptDrops(
true);
80 setAutoExpandDelay(800);
82 setItemsExpandable(
true);
83 setRootIsDecorated(
true);
84 setAllColumnsShowFocus(
true);
85 setSelectionMode(QAbstractItemView::ExtendedSelection);
88 setEditTriggers(editTriggers() ^ QAbstractItemView::DoubleClicked);
92 m_popup->setTitle(tr(
"Bookmarks"));
93 auto const addMenuAction =
99 auto *
const action =
new QAction(pix, text,
this);
101 std::forward<
decltype(slot)>(slot));
106 addMenuAction(
NewFolder, tr(
"New folder"), MI::newFolder::icon(),
108 if (!selectedIndexes().empty()) {
122 addMenuAction(
ChangeFolder, tr(
"Rename folder"), MI::changeFolder::icon(),
125 edit(currentIndex());
129 MI::editBookmark::icon(),
131 QModelIndex
const index = currentIndex();
133 auto *
const module = m_bookmarksModel->module(index);
135 QStringLiteral(
"%1 (%2)")
139 : QObject::tr(
"unknown")),
140 index.data().toString(),
143 if (d.exec() == QDialog::Accepted) {
146 d.descriptionText());
150 MI::sortFolderBookmarks::icon(),
156 MI::sortAllBookmarks::icon(),
161 m_bookmarksModel->removeRow(m_extraItem.row(),
162 m_extraItem.parent());
163 if (m_bookmarksModel->insertRows(numRows - 1, 1))
165 m_bookmarksModel->index(numRows - 1, 0);
169 MI::importBookmarks::icon(),
172 QString
const fileName =
173 QFileDialog::getOpenFileName(
175 QObject::tr(
"Import bookmarks"),
178 if (!fileName.isEmpty())
182 MI::exportBookmarks::icon(),
185 QString
const fileName =
186 QFileDialog::getSaveFileName(
188 QObject::tr(
"Export Bookmarks"),
191 if (!fileName.isEmpty())
195 MI::printBookmarks::icon(),
202 BtPrinter::KeyTreeItem::Settings::CompleteShort};
203 QModelIndexList items(selectedIndexes());
204 while (!items.empty()) {
205 QModelIndex
const index(items.takeFirst());
212 int const numChildren =
214 for (
int i = 0; i < numChildren; i++)
215 items.append(index.model()->index(i,
225 this}.printKeyTree(tree);
229 MI::deleteItems::icon(),
234 tr(
"Do you really want to delete the selected "
235 "items and folders?"),
236 QMessageBox::Yes | QMessageBox::No,
237 QMessageBox::No) == QMessageBox::Yes)
245 [
this](QModelIndex
const & index) {
251 if (modifiers != Qt::NoModifier || !index.isValid())
258 QList<CSwordModuleInfo *>() << mod,
261 BT_CONNECT(
this, &CBookmarkIndex::customContextMenuRequested,
262 [
this](QPoint
const & p) {
264 QModelIndex
const i(indexAt(p));
265 QModelIndexList
const items(selectedIndexes());
266 if (items.isEmpty()) {
271 }
else if (items.count() == 1) {
277 }
else if (!i.isValid()) {
298 QModelIndex
const itemUnderPointer(
299 indexAt(mapFromGlobal(QCursor::pos())));
300 if (itemUnderPointer.isValid()
309 QStringLiteral(
"%1:%2")
316 tr(
"The work to which the bookmark "
317 "points to is not installed."));
337 QTreeView::mouseReleaseEvent(event);
343 for (
auto const & widgetItem : selectedIndexes()) {
344 if (!widgetItem.isValid())
350 m_bookmarksModel->module(widgetItem);
351 const QString moduleName =
module ? module->name() : QString();
352 bookmarks.append({moduleName,
361 if (event->mimeData()->hasFormat(QStringLiteral(
"BibleTime/Bookmark"))) {
362 event->acceptProposedAction();
363 setState(DraggingState);
365 QAbstractItemView::dragEnterEvent(event);
371 QTreeView::dragMoveEvent(event);
373 event->acceptProposedAction();
378 viewport()->update();
382 setState(QAbstractItemView::NoState);
383 viewport()->update();
388 QTreeView::paintEvent(event);
391 if (state() != QAbstractItemView::DraggingState)
395 static int halfPixHeight;
396 static bool arrowInitialized =
false;
399 if (!arrowInitialized) {
400 arrowInitialized =
true;
404 halfPixHeight = pix.height() / 2;
411 QRect
const rect = visualRect(index);
412 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
414 yCoord = rect.bottom() - halfPixHeight;
416 yCoord = rect.top() - halfPixHeight - 1;
420 QRect
const rect = visualRect(index);
422 > rect.bottom() - (2 * rect.height() / 3))
424 yCoord = rect.bottom() - halfPixHeight;
425 xCoord = QApplication::isRightToLeft()
426 ? (rect.right() - indentation())
427 : (rect.left() + indentation());
429 yCoord = rect.top() - halfPixHeight - 1;
430 xCoord = QApplication::isRightToLeft()
434 }
else if (index.isValid()) {
435 QRect
const rect = visualRect(index);
436 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
437 yCoord = rect.top() - halfPixHeight - 1;
440 yCoord = rect.top() - halfPixHeight - 1;
441 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
444 QPainter{this->viewport()}.drawPixmap(xCoord, yCoord, pix);
450 auto const connection =
452 [
this](QModelIndex
const & index) { expand(index); });
453 auto cleanup = qScopeGuard([&connection]()
noexcept
454 { disconnect(connection); });
455 auto const pos =
event->position().toPoint();
456 auto const index = indexAt(pos);
457 QModelIndex parentIndex;
458 int indexUnderParent = 0;
461 if (index.isValid()) {
463 QRect
const rect = visualRect(index);
464 if (pos.y() > rect.bottom() - (2 * rect.height() / 3)) {
467 parentIndex = index.parent();
468 indexUnderParent = index.row();
472 parentIndex = index.parent();
473 indexUnderParent = index.row();
474 QRect
const rect = visualRect(index);
475 if (pos.y() > rect.bottom() - rect.height() / 2)
478 parentIndex = index.parent();
479 indexUnderParent = index.row();
486 if (event->source() !=
this) {
489 dynamic_cast<BTMimeData const *
>(event->mimeData()))
492 auto const & bookmark = mdata->bookmarks().first();
493 QString moduleName(bookmark.module());
494 QString keyText(bookmark.key());
495 QString description(bookmark.description());
498 std::move(moduleName));
506 std::move(description));
511 bool bookmarksOnly =
true;
512 bool targetIncluded =
false;
513 bool moreThanOneFolder =
false;
515 QModelIndexList
const list = selectedIndexes();
516 QModelIndexList newList;
518 for (
auto const & index : list) {
520 bookmarksOnly =
false;
522 if (list.count() > 1) {
523 moreThanOneFolder =
true;
528 targetIncluded =
true;
532 newList.append(index);
536 if (!bookmarksOnly && list.count() == 1) {
537 newList.append(list[0]);
538 }
else if (!bookmarksOnly && list.count() > 1) {
539 moreThanOneFolder =
true;
542 if (moreThanOneFolder) {
543 QToolTip::showText(QCursor::pos(), tr(
"Can drop only bookmarks or one folder"));
546 if (targetIncluded) {
547 QToolTip::showText(QCursor::pos(), tr(
"Can't drop folder into the folder itself or into its subfolder"));
552 std::unique_ptr<QMenu> dropPopupMenu{
new QMenu{
this}};
553 dropPopupMenu->setEnabled(!newList.empty());
554 QAction *
const copy = dropPopupMenu->addAction(tr(
"Copy"));
555 QAction *
const move = dropPopupMenu->addAction(tr(
"Move"));
556 QAction *
const dropAction = dropPopupMenu->exec(QCursor::pos());
557 dropPopupMenu.reset();
559 if (dropAction == copy) {
561 }
else if (dropAction == move) {
568 setState(QAbstractItemView::NoState);
593 while (!items.empty()) {
594 QModelIndex
const index = items.takeFirst();
599 for (
int i = 0; i < numChildren; i++)
600 items.append(index.model()->index(i, 0, index));
608 tr(
"Drag references from text views to this view"));
617 QTreeView::leaveEvent(event);
624 QList<QPersistentModelIndex> list;
625 for (
auto const & i : selectedIndexes())
628 for (
auto const & i : list)
629 model()->removeRows(i.row(), 1, i.parent());
643 QDrag *
const drag =
new QDrag{
this};
644 drag->setMimeData(mData);
647 viewport()->update();
653 QModelIndex
const itemUnderPointer = indexAt(event->pos());
654 if (itemUnderPointer.isValid()
656 && !(event->modifiers() & Qt::ShiftModifier))
660 if (!itemUnderPointer.isValid() || itemUnderPointer ==
m_extraItem) {
667 QTreeView::mouseMoveEvent(event);
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
QList< BookmarkItem > ItemList
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void copyItems(int row, const QModelIndex &parent, const QModelIndexList &toCopy)
Copies item to target position.
bool isBookmark(const QModelIndex &index) const
bool hasDescendant(const QModelIndex &baseIndex, const QModelIndex &testIndex) const
bool isFolder(const QModelIndex &index) const
void sortItems(QModelIndex const &parent=QModelIndex(), Qt::SortOrder const order=Qt::AscendingOrder)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QString description(const QModelIndex &index) const
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void setDescription(const QModelIndex &index, const QString &description)
set descritpion for index.
bool load(QString fileName=QString(), const QModelIndex &rootItem=QModelIndex())
Import bookmarks from file.
CSwordModuleInfo * module(const QModelIndex &index) const
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QModelIndex addFolder(int row, const QModelIndex &parent, const QString &name=QString())
add new folder.
bool save(QString fileName=QString(), const QModelIndex &rootItem=QModelIndex())
Save bookmarks or specified branch to file.
QModelIndex addBookmark(int const row, QModelIndex const &parent, CSwordModuleInfo const &module, QString const &key, QString const &description=QString(), QString const &title=QString())
add new item with given parameters
QString key(const QModelIndex &index) const
DisplayOptions getDisplayOptions() const
FilterOptions getFilterOptions() const
A dialog box for editing bookmarks.
RegularIcon const icon_pointing_arrow
static BtIcons & instance()
Manages the print item queue and printing.
void createReadDisplayWindow(QList< CSwordModuleInfo * >, QString const &)
Emitted when a module should be opened.
void startDrag(Qt::DropActions supportedActions) override
QPoint m_dragMovementPosition
BtBookmarksModel * m_bookmarksModel
void mouseReleaseEvent(QMouseEvent *event) override
void leaveEvent(QEvent *event) override
int m_mouseReleaseEventModifiers
void dragEnterEvent(QDragEnterEvent *event) override
void mouseMoveEvent(QMouseEvent *event) override
void magInfoProvided(Rendering::InfoType const, QString const &data)
QModelIndex m_previousEventItem
void paintEvent(QPaintEvent *event) override
CBookmarkIndex(QWidget *const parent=nullptr)
QAction * m_actions[ActionCount]
void dragLeaveEvent(QDragLeaveEvent *event) override
void dragMoveEvent(QDragMoveEvent *event) override
bool hasBookmarksRecursively(QModelIndexList selected) const
QPersistentModelIndex m_extraItem
void dropEvent(QDropEvent *event) override
bool enableAction(QModelIndex const &index, MenuAction const type) const
CSwordModuleInfo * findModuleByName(const QString &name) const
Searches for a module with the given name.
static CSwordBackend & instance() noexcept
std::list< KeyTreeItem > KeyTree
QString fileDialogFilter()
QMessageBox::StandardButton showQuestion(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)