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,
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;
403 halfPixHeight = pix.height() / 2;
410 QRect
const rect = visualRect(index);
411 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
413 yCoord = rect.bottom() - halfPixHeight;
415 yCoord = rect.top() - halfPixHeight - 1;
419 QRect
const rect = visualRect(index);
421 > rect.bottom() - (2 * rect.height() / 3))
423 yCoord = rect.bottom() - halfPixHeight;
424 xCoord = QApplication::isRightToLeft()
425 ? (rect.right() - indentation())
426 : (rect.left() + indentation());
428 yCoord = rect.top() - halfPixHeight - 1;
429 xCoord = QApplication::isRightToLeft()
433 }
else if (index.isValid()) {
434 QRect
const rect = visualRect(index);
435 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
436 yCoord = rect.top() - halfPixHeight - 1;
439 yCoord = rect.top() - halfPixHeight - 1;
440 xCoord = QApplication::isRightToLeft() ? rect.right() : rect.left();
443 QPainter{this->viewport()}.drawPixmap(xCoord, yCoord, pix);
449 auto const connection =
451 [
this](QModelIndex
const & index) { expand(index); });
452 auto cleanup = qScopeGuard([&connection]()
noexcept
453 { disconnect(connection); });
454 auto const pos =
event->position().toPoint();
455 auto const index = indexAt(pos);
456 QModelIndex parentIndex;
457 int indexUnderParent = 0;
460 if (index.isValid()) {
462 QRect
const rect = visualRect(index);
463 if (pos.y() > rect.bottom() - (2 * rect.height() / 3)) {
466 parentIndex = index.parent();
467 indexUnderParent = index.row();
471 parentIndex = index.parent();
472 indexUnderParent = index.row();
473 QRect
const rect = visualRect(index);
474 if (pos.y() > rect.bottom() - rect.height() / 2)
477 parentIndex = index.parent();
478 indexUnderParent = index.row();
485 if (event->source() !=
this) {
488 dynamic_cast<BTMimeData const *
>(event->mimeData()))
491 auto const & bookmark = mdata->bookmarks().first();
492 QString moduleName(bookmark.module());
493 QString keyText(bookmark.key());
494 QString description(bookmark.description());
497 std::move(moduleName));
505 std::move(description));
510 bool bookmarksOnly =
true;
511 bool targetIncluded =
false;
512 bool moreThanOneFolder =
false;
514 QModelIndexList
const list = selectedIndexes();
515 QModelIndexList newList;
517 for (
auto const & index : list) {
519 bookmarksOnly =
false;
521 if (list.count() > 1) {
522 moreThanOneFolder =
true;
527 targetIncluded =
true;
531 newList.append(index);
535 if (!bookmarksOnly && list.count() == 1) {
536 newList.append(list[0]);
537 }
else if (!bookmarksOnly && list.count() > 1) {
538 moreThanOneFolder =
true;
541 if (moreThanOneFolder) {
542 QToolTip::showText(QCursor::pos(), tr(
"Can drop only bookmarks or one folder"));
545 if (targetIncluded) {
546 QToolTip::showText(QCursor::pos(), tr(
"Can't drop folder into the folder itself or into its subfolder"));
551 std::unique_ptr<QMenu> dropPopupMenu{
new QMenu{
this}};
552 dropPopupMenu->setEnabled(!newList.empty());
553 QAction *
const copy = dropPopupMenu->addAction(tr(
"Copy"));
554 QAction *
const move = dropPopupMenu->addAction(tr(
"Move"));
555 QAction *
const dropAction = dropPopupMenu->exec(QCursor::pos());
556 dropPopupMenu.reset();
558 if (dropAction == copy) {
560 }
else if (dropAction == move) {
567 setState(QAbstractItemView::NoState);
592 while (!items.empty()) {
593 QModelIndex
const index = items.takeFirst();
598 for (
int i = 0; i < numChildren; i++)
599 items.append(index.model()->index(i, 0, index));
607 tr(
"Drag references from text views to this view"));
616 QTreeView::leaveEvent(event);
623 QList<QPersistentModelIndex> list;
624 for (
auto const & i : selectedIndexes())
627 for (
auto const & i : list)
628 model()->removeRows(i.row(), 1, i.parent());
642 QDrag *
const drag =
new QDrag{
this};
643 drag->setMimeData(mData);
646 viewport()->update();
652 QModelIndex
const itemUnderPointer = indexAt(event->pos());
653 if (itemUnderPointer.isValid()
655 && !(event->modifiers() & Qt::ShiftModifier))
659 if (!itemUnderPointer.isValid() || itemUnderPointer ==
m_extraItem) {
666 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.
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
QIcon const & icon_pointing_arrow()
QString fileDialogFilter()
QMessageBox::StandardButton showQuestion(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)