7#include "BookmarkManagerDialog.h" 
    8#include "BookmarkManager.h" 
    9#include "BookmarkManager_p.h" 
   10#include "BranchFilterProxyModel.h" 
   11#include "EditBookmarkDialog.h" 
   12#include "FileManager.h" 
   13#include "GeoDataCoordinates.h" 
   14#include "GeoDataDocument.h" 
   15#include "GeoDataDocumentWriter.h" 
   16#include "GeoDataExtendedData.h" 
   17#include "GeoDataFolder.h" 
   18#include "GeoDataIconStyle.h" 
   19#include "GeoDataLookAt.h" 
   20#include "GeoDataPlacemark.h" 
   21#include "GeoDataPoint.h" 
   22#include "GeoDataStyle.h" 
   23#include "GeoDataTreeModel.h" 
   24#include "GeoDataTypes.h" 
   25#include "MarbleDebug.h" 
   26#include "MarbleDirs.h" 
   28#include "MarblePlacemarkModel.h" 
   29#include "NewBookmarkFolderDialog.h" 
   30#include <KmlElementDictionary.h> 
   36#include <QSortFilterProxyModel> 
   55class BookmarkManagerDialogPrivate
 
   57    Q_DECLARE_TR_FUNCTIONS(BookmarkManagerDialogPrivate)
 
   60    BookmarkManagerDialog *m_parent;
 
   62    BookmarkManager *
const m_manager;
 
   64    GeoDataTreeModel *
const m_treeModel;
 
   66    QSortFilterProxyModel m_folderFilterModel;
 
   68    QPersistentModelIndex m_selectedFolder;
 
   70    BranchFilterProxyModel m_branchFilterModel;
 
   72    BookmarkManagerDialogPrivate(BookmarkManagerDialog *parent, MarbleModel *model);
 
   74    void initializeFoldersView(GeoDataTreeModel *treeModel);
 
   76    void initializeBookmarksView(GeoDataTreeModel *treeModel);
 
   78    void handleFolderSelection(
const QModelIndex &index);
 
   80    void updateButtonState();
 
   90    void deleteBookmark();
 
   92    void discardChanges();
 
   94    QModelIndex bookmarkTreeIndex(
const QModelIndex &bookmark) 
const;
 
   96    QModelIndex folderTreeIndex(
const QModelIndex &index) 
const;
 
   97    GeoDataContainer *selectedFolder();
 
   99    void selectFolder(
const QString &name = QString(), 
const QModelIndex &index = QModelIndex());
 
  101    void importBookmarksRecursively(GeoDataContainer *source, GeoDataContainer *destination, 
bool &replaceAll, 
bool &skipAll);
 
  103    GeoDataDocument *bookmarkDocument();
 
  106BookmarkManagerDialogPrivate::BookmarkManagerDialogPrivate(BookmarkManagerDialog *parent, 
MarbleModel *model)
 
  108    , m_manager(model->bookmarkManager())
 
  109    , m_treeModel(model->treeModel())
 
  110    , m_folderFilterModel()
 
  111    , m_branchFilterModel()
 
  118void BookmarkManagerDialogPrivate::handleFolderSelection(
const QModelIndex &index)
 
  124    Q_ASSERT(index.
model() == &m_folderFilterModel);
 
  125    if (m_selectedFolder.
isValid() && m_parent->foldersTreeView->selectionModel()->selectedIndexes().contains(m_selectedFolder)) {
 
  127        m_parent->foldersTreeView->selectionModel()->clear();
 
  130        m_selectedFolder = index;
 
  131        m_branchFilterModel.setBranchIndex(m_treeModel, folderTreeIndex(index));
 
  132        m_parent->bookmarksListView->setRootIndex(m_branchFilterModel.mapFromSource(folderTreeIndex(index)));
 
  133        m_parent->bookmarksListView->selectionModel()->clear();
 
  137void BookmarkManagerDialogPrivate::updateButtonState()
 
  139    bool const hasFolderSelection = !m_parent->foldersTreeView->selectionModel()->selectedIndexes().isEmpty();
 
  140    m_parent->renameFolderButton->setEnabled(hasFolderSelection);
 
  141    m_parent->removeFolderButton->setEnabled(hasFolderSelection);
 
  143    bool const hasBookmarkSelection = !m_parent->bookmarksListView->selectionModel()->selectedIndexes().isEmpty();
 
  144    m_parent->editBookmarkButton->setEnabled(hasBookmarkSelection);
 
  145    m_parent->removeBookmarkButton->setEnabled(hasBookmarkSelection);
 
  148void BookmarkManagerDialogPrivate::addNewFolder()
 
  152        m_manager->addNewBookmarkFolder(selectedFolder(), dialog->folderName());
 
  153        selectFolder(dialog->folderName(), m_selectedFolder);
 
  158void BookmarkManagerDialogPrivate::renameFolder()
 
  160    auto folder = geodata_cast<GeoDataFolder>(selectedFolder());
 
  163        dialog->setFolderName(folder->name());
 
  166            m_manager->renameBookmarkFolder(folder, dialog->folderName());
 
  168        selectFolder(dialog->folderName(), parentIndex);
 
  173void BookmarkManagerDialogPrivate::deleteFolder()
 
  175    auto folder = geodata_cast<GeoDataFolder>(selectedFolder());
 
  177        if (folder->size() > 0) {
 
  179                tr(
"The folder %1 is not empty. Removing it will delete all bookmarks it contains. Are you sure you want to delete the folder?")
 
  180                    .
arg(folder->name());
 
  187        QString parent = 
static_cast<GeoDataContainer *
>(folder->parent())->name();
 
  189        m_manager->removeBookmarkFolder(folder);
 
  190        selectFolder(parent, greatParentIndex);
 
  194void BookmarkManagerDialogPrivate::editBookmark()
 
  196    QModelIndexList selection = m_parent->bookmarksListView->selectionModel()->selectedIndexes();
 
  197    if (selection.size() == 1) {
 
  198        QModelIndex index = m_branchFilterModel.mapToSource(selection.first());
 
  200        auto object = qvariant_cast<GeoDataObject *>(index.
data(MarblePlacemarkModel::ObjectPointerRole));
 
  202        auto bookmark = geodata_cast<GeoDataPlacemark>(
object);
 
  211        Q_ASSERT(folderIndex.
isValid());
 
  212        auto folderObject = qvariant_cast<GeoDataObject *>(folderIndex.
data(MarblePlacemarkModel::ObjectPointerRole));
 
  213        Q_ASSERT(folderObject);
 
  214        auto folder = geodata_cast<GeoDataFolder>(folderObject);
 
  218        dialog->setName(bookmark->name());
 
  219        if (bookmark->lookAt()) {
 
  220            dialog->setRange(bookmark->lookAt()->range());
 
  222        dialog->setCoordinates(bookmark->coordinate());
 
  223        dialog->setDescription(bookmark->description());
 
  224        dialog->setFolderName(folder->name());
 
  225        dialog->setIconLink(bookmark->style()->iconStyle().iconPath());
 
  227            bookmark->setName(dialog->name());
 
  228            bookmark->setDescription(dialog->description());
 
  229            bookmark->setCoordinate(dialog->coordinates());
 
  230            GeoDataStyle::Ptr newStyle(
new GeoDataStyle(*bookmark->style()));
 
  231            newStyle->iconStyle().setIconPath(dialog->iconLink());
 
  232            bookmark->setStyle(newStyle);
 
  233            if (bookmark->lookAt()) {
 
  234                bookmark->lookAt()->setCoordinates(dialog->coordinates());
 
  235                bookmark->lookAt()->setRange(dialog->range());
 
  236            } 
else if (dialog->range()) {
 
  237                auto lookat = 
new GeoDataLookAt;
 
  238                lookat->setCoordinates(dialog->coordinates());
 
  239                lookat->setRange(dialog->range());
 
  240                bookmark->setAbstractView(lookat);
 
  242            m_manager->updateBookmark(bookmark);
 
  244            if (folder->name() != dialog->folder()->name()) {
 
  245                GeoDataPlacemark newBookmark(*bookmark);
 
  246                m_manager->removeBookmark(bookmark);
 
  247                m_manager->addBookmark(dialog->folder(), newBookmark);
 
  254void BookmarkManagerDialogPrivate::deleteBookmark()
 
  256    const QModelIndexList selection = m_parent->bookmarksListView->selectionModel()->selectedIndexes();
 
  258    if (selection.size() != 1) {
 
  262    const QModelIndex bookmarkIndex = m_branchFilterModel.mapToSource(selection.first());
 
  263    auto folder = geodata_cast<GeoDataFolder>(selectedFolder());
 
  268    auto bookmark = geodata_cast<GeoDataPlacemark>(folder->child(bookmarkIndex.
row()));
 
  273    m_manager->removeBookmark(bookmark);
 
  276void BookmarkManagerDialogPrivate::discardChanges()
 
  278    m_manager->loadFile(QStringLiteral(
"bookmarks/bookmarks.kml"));
 
  282void BookmarkManagerDialogPrivate::selectFolder(
const QString &name, 
const QModelIndex &parent)
 
  285        Q_ASSERT(parent.
model() == &m_folderFilterModel);
 
  289        QModelIndex documentTreeIndex = m_treeModel->index(bookmarkDocument());
 
  291        Q_ASSERT(folderFilterIndex.
isValid());
 
  292        m_parent->foldersTreeView->setCurrentIndex(folderFilterIndex);
 
  293        handleFolderSelection(folderFilterIndex);
 
  297    for (
int i = 0; i < m_folderFilterModel.
rowCount(parent); ++i) {
 
  299        if (childIndex.
data().
toString() == name && m_selectedFolder != childIndex) {
 
  300            m_parent->foldersTreeView->setCurrentIndex(childIndex);
 
  301            handleFolderSelection(childIndex);
 
  305            selectFolder(name, childIndex);
 
  313    Q_ASSERT(index.
model() == &m_folderFilterModel);
 
  315    Q_ASSERT(treeModelIndex.
isValid());
 
  316    Q_ASSERT(treeModelIndex.
model() == m_treeModel);
 
  317    return treeModelIndex;
 
  320GeoDataContainer *BookmarkManagerDialogPrivate::selectedFolder()
 
  322    if (m_selectedFolder.
isValid()) {
 
  323        auto object = qvariant_cast<GeoDataObject *>(m_selectedFolder.
data(MarblePlacemarkModel::ObjectPointerRole));
 
  325        auto container = 
dynamic_cast<GeoDataContainer *
>(object);
 
  329        return bookmarkDocument();
 
  333void BookmarkManagerDialogPrivate::initializeFoldersView(GeoDataTreeModel *treeModel)
 
  340    m_parent->foldersTreeView->setModel(&m_folderFilterModel);
 
  342    m_parent->foldersTreeView->setHeaderHidden(
true);
 
  343    for (
int i = 1; i < m_treeModel->columnCount(); ++i) {
 
  344        m_parent->foldersTreeView->hideColumn(i);
 
  346    m_parent->foldersTreeView->setRootIndex(m_folderFilterModel.
mapFromSource(m_treeModel->index(bookmarkDocument())));
 
  348    m_parent->connect(m_parent->foldersTreeView, SIGNAL(clicked(
QModelIndex)), m_parent, SLOT(handleFolderSelection(
QModelIndex)));
 
  349    m_parent->connect(m_parent->foldersTreeView->selectionModel(),
 
  352                      SLOT(updateButtonState()));
 
  353    m_parent->connect(m_parent->renameFolderButton, SIGNAL(clicked(
bool)), m_parent, SLOT(renameFolder()));
 
  354    m_parent->connect(m_parent->newFolderButton, SIGNAL(clicked(
bool)), m_parent, SLOT(addNewFolder()));
 
  355    m_parent->connect(m_parent->removeFolderButton, SIGNAL(clicked(
bool)), m_parent, SLOT(deleteFolder()));
 
  358void BookmarkManagerDialogPrivate::initializeBookmarksView(GeoDataTreeModel *treeModel)
 
  360    m_branchFilterModel.setSourceModel(treeModel);
 
  362    m_parent->bookmarksListView->setModel(&m_branchFilterModel);
 
  365    m_parent->connect(m_parent->bookmarksListView->selectionModel(),
 
  368                      SLOT(updateButtonState()));
 
  369    m_parent->connect(m_parent->editBookmarkButton, SIGNAL(clicked(
bool)), m_parent, SLOT(editBookmark()));
 
  370    m_parent->connect(m_parent->removeBookmarkButton, SIGNAL(clicked(
bool)), m_parent, SLOT(deleteBookmark()));
 
  373BookmarkManagerDialog::BookmarkManagerDialog(MarbleModel *model, 
QWidget *parent)
 
  375    , d(new BookmarkManagerDialogPrivate(this, model))
 
  378    bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
 
  379    importButton->setVisible(!smallScreen);
 
  380    exportButton->setVisible(!smallScreen);
 
  381    foldersLabel->setVisible(!smallScreen);
 
  382    bookmarkLabel->setVisible(!smallScreen);
 
  384    d->initializeFoldersView(d->m_treeModel);
 
  385    d->initializeBookmarksView(d->m_treeModel);
 
  386    d->updateButtonState();
 
  388    connect(
this, SIGNAL(accepted()), SLOT(saveBookmarks()));
 
  389    connect(
this, SIGNAL(rejected()), SLOT(discardChanges()));
 
  390    connect(exportButton, SIGNAL(clicked()), 
this, SLOT(exportBookmarks()));
 
  391    connect(importButton, SIGNAL(clicked()), 
this, SLOT(importBookmarks()));
 
  396BookmarkManagerDialog::~BookmarkManagerDialog()
 
  401void BookmarkManagerDialog::saveBookmarks()
 
  403    d->m_manager->updateBookmarkFile();
 
  406void BookmarkManagerDialog::exportBookmarks()
 
  409                                                    tr(
"Export Bookmarks"), 
 
  411                                                    tr(
"KML files (*.kml)"));
 
  414        if (!GeoDataDocumentWriter::write(fileName, *d->bookmarkDocument())) {
 
  415            mDebug() << 
"Could not write the bookmarks file" << fileName;
 
  416            QString const text = tr(
"Unable to save bookmarks. Please check that the file is writable.");
 
  422void BookmarkManagerDialog::importBookmarks()
 
  429    GeoDataDocument *
import = BookmarkManager::openFile(file);
 
  431        QString const text = tr(
"The file %1 cannot be opened as a KML file.").
arg(file);
 
  435    GeoDataDocument *current = d->bookmarkDocument();
 
  437    bool skipAll = 
false;
 
  438    bool replaceAll = 
false;
 
  439    d->importBookmarksRecursively(
import, current, skipAll, replaceAll);
 
  444void BookmarkManagerDialogPrivate::importBookmarksRecursively(GeoDataContainer *source, GeoDataContainer *destination, 
bool &replaceAll, 
bool &skipAll)
 
  446    for (GeoDataFolder *newFolder : source->folderList()) {
 
  447        GeoDataFolder *existingFolder = m_manager->addNewBookmarkFolder(destination, newFolder->name());
 
  448        importBookmarksRecursively(newFolder, existingFolder, skipAll, replaceAll);
 
  449        for (GeoDataPlacemark *newPlacemark : newFolder->placemarkList()) {
 
  450            bool added = skipAll;
 
  453            GeoDataPlacemark *existingPlacemark = m_manager->bookmarkAt(m_manager->document(), newCoordinate);
 
  454            if (existingPlacemark) {
 
  460                if (existingPlacemark->name() == newPlacemark->name() && existingPlacemark->description() == newPlacemark->description()) {
 
  465                QString const intro = tr(
"The file contains a bookmark that already exists among your Bookmarks.");
 
  466                QString const newBookmark = tr(
"Imported bookmark");
 
  467                QString const existingBookmark = tr(
"Existing bookmark");
 
  468                QString const question = tr(
"Do you want to replace the existing bookmark with the imported one?");
 
  470                    "<p>%1</p><table><tr><td>%2</td><td><b>%3 / %4</b></td></tr>" 
  471                    "<tr><td>%5</td><td><b>%6 / %7</b></td></tr></table><p>%8</p>");
 
  472                html = html.
arg(intro,
 
  474                                existingFolder->name(),
 
  475                                existingPlacemark->name(),
 
  478                                newPlacemark->name(),
 
  492                if (
messageBox->clickedButton() == replaceAllButton) {
 
  494                } 
else if (
messageBox->clickedButton() == skipAllButton) {
 
  497                } 
else if (
messageBox->clickedButton() == skipButton) {
 
  500                } 
else if (
messageBox->clickedButton() != replaceButton) {
 
  505                if (
messageBox->clickedButton() == replaceButton || replaceAll) {
 
  506                    m_manager->removeBookmark(existingPlacemark);
 
  507                    m_manager->addBookmark(existingFolder, *newPlacemark);
 
  509                    mDebug() << 
"Placemark " << newPlacemark->name() << 
" replaces " << existingPlacemark->name();
 
  517                m_manager->addBookmark(existingFolder, *newPlacemark);
 
  523GeoDataDocument *BookmarkManagerDialogPrivate::bookmarkDocument()
 
  525    return m_manager->document();
 
  528void BookmarkManagerDialog::setButtonBoxVisible(
bool visible)
 
  530    buttonBox->setVisible(visible);
 
  532        disconnect(
this, SIGNAL(rejected()), 
this, SLOT(discardChanges()));
 
  533        connect(
this, SIGNAL(rejected()), SLOT(saveBookmarks()));
 
  539#include "moc_BookmarkManagerDialog.cpp" 
This file contains the headers for MarbleModel.
 
A 3d point representation.
 
The data model (not based on QAbstractModel) for a MarbleWidget.
 
ButtonCode messageBox(QWidget *parent, DialogType type, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const KGuiItem &cancelAction=KStandardGuiItem::cancel(), const QString &dontShowAskAgainName=QString(), Options options=Notify)
 
QString name(StandardAction id)
 
Binds a QML item to a specific geodetic location in screen coordinates.
 
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
 
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
 
StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
 
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
 
QVariant data(int role) const const
 
bool isValid() const const
 
const QAbstractItemModel * model() const const
 
QModelIndex parent() const const
 
QVariant data(int role) const const
 
bool isValid() const const
 
QModelIndex parent() const const
 
void setFilterKeyColumn(int column)
 
void setFilterRegularExpression(const QRegularExpression ®ularExpression)
 
virtual bool hasChildren(const QModelIndex &parent) const const override
 
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
 
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const const override
 
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const override
 
virtual int rowCount(const QModelIndex &parent) const const override
 
virtual void setSourceModel(QAbstractItemModel *sourceModel) override
 
QString arg(Args &&... args) const const
 
bool isEmpty() const const
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
QString toString() const const