/***************************** LICENSE START ***********************************

 Copyright 2013 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <QtGlobal>
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QMap>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMessageBox>
#include <QPainter>
#include <QPair>
#include <QPlainTextEdit>
#include <QStyleOptionViewItem>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvQBookmarks.h"

#include "MvQ.h"
#include "MvQContextMenu.h"
#include "MvQDropTarget.h"
#include "MvQFileBrowser.h"
#include "MvQFolderViewBase.h"
#include "MvQKeyManager.h"
#include "MvQKeyModel.h"
#include "MvQIconProvider.h"
#include "MvQMethods.h"

#include "Folder.h"
#include "IconClass.h"
#include "IconFactory.h"
#include "IconObject.h"
#include "MvKeyProfile.h"
#include "Path.h"

MvQKeyManager* MvQBookmarks::manager_ = nullptr;
MvQBookmarksModel* MvQBookmarks::model_ = nullptr;
MvKeyProfile* MvQBookmarks::prof_ = nullptr;

//=============================================
//
// MvQBookmarksModel
//
//=============================================

QVariant MvQBookmarksModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || index.column() != 0 ||
        (role != Qt::DisplayRole && role != Qt::ToolTipRole &&
         role != Qt::DecorationRole && role != Qt::UserRole)) {
        return {};
    }

    MvKey* key = profile_->at(index.row());
    if (role == Qt::DisplayRole) {
        return QString::fromStdString(key->shortName());
    }
    else if (role == Qt::ToolTipRole) {
        std::string cntStr = key->metaData("path_count");
        if (!cntStr.empty())
            return "Bookmark for a <b>group of folders</b>";
        else {
            // Check if path exist
            Path p = Folder::top()->path();
            if (p.add(key->name()).exists())
                return QString::fromStdString(key->name());
            else
                return "<b>Folder does not exsist!</b><br>" + QString::fromStdString(key->name());
        }
    }
    else if (role == Qt::DecorationRole) {
        return MvQIconProvider::bookmarkPixmap(key->name(), 18);
    }
    else if (role == Qt::UserRole) {
        std::string cntStr = key->metaData("path_count");
        if (!cntStr.empty())
            return {};
        else
            return QString::fromStdString(key->name());
    }

    return {};
}

//================================================
//
//  MvQBookmarks
//
//================================================

MvQBookmarks::MvQBookmarks(QWidget* parent) :
    QObject(parent)
{
}

// Static
void MvQBookmarks::init()
{
    if (manager_)
        return;

    manager_ = new MvQKeyManager(MvQKeyManager::BookmarkType);
    manager_->loadProfiles();

    prof_ = nullptr;
    if (manager_->data().size() > 0) {
        prof_ = manager_->data().at(0);
    }
    else {
        prof_ = new MvKeyProfile("custom");
        manager_->addProfile(prof_);
    }

    model_ = new MvQBookmarksModel(prof_);
}

// Static
MvQContextItemSet* MvQBookmarks::cmSet()
{
    static MvQContextItemSet cm("Bookmarks");
    return &cm;
}

// Static
void MvQBookmarks::save()
{
    manager_->saveProfiles();
}

bool MvQBookmarks::isBookmark(QString path)
{
    MvKeyProfile* prof = model_->profile();
    if (!prof)
        return false;

    std::string p = path.toStdString();

    for (unsigned int i = 0; i < prof->size(); i++) {
        if (prof->at(i)->name() == p)
            return true;
    }
    return false;
}

void MvQBookmarks::defaultCommand(const QModelIndex& index)
{
    MvKeyProfile* prof = model_->profile();
    MvKey* key = nullptr;
    if (prof && index.row() <= static_cast<int>(prof->size() - 1)) {
        key = prof->at(index.row());
    }
    else
        return;

    if (!key)
        return;

    QString fullName = QString::fromStdString(key->name());
    if (!isFolderGroup(key))
        emit lookupOrOpenInTab(fullName);
    else
        emit openGroupInTabs(getPathsFromKey(key));
}

void MvQBookmarks::command(QString name, const QModelIndex& index)
{
    if (!index.isValid())
        return;

    MvKeyProfile* prof = model_->profile();
    MvKey* key = nullptr;
    if (prof && index.row() <= static_cast<int>(prof->size() - 1)) {
        key = prof->at(index.row());
    }
    else
        return;

    if (!key)
        return;

    QString fullName = QString::fromStdString(key->name());

    if (name == "gotoInCurrentTab" && !isFolderGroup(key)) {
        emit openInBrowser(fullName);
    }
    if (name == "lookupOrOpenInTab" && !isFolderGroup(key)) {
        emit lookupOrOpenInTab(fullName);
    }
    else if (name == "openInNewTab" && !isFolderGroup(key)) {
        emit openInNewTab(fullName);
    }
    else if (name == "openInNewWin" && !isFolderGroup(key)) {
        emit openInWin(fullName);
    }
    else if (name == "editEntry") {
        if (editItem(index))
            MvQBookmarks::save();
    }
    else if (name == "duplicateEntry") {
        if (duplicateItem(index))
            MvQBookmarks::save();
    }
    else if (name == "removeEntry") {
        if (deleteItem(index))
            MvQBookmarks::save();
    }
    else if (name == "openGroup") {
        emit openGroupInTabs(getPathsFromKey(key));
    }
    else if (name == "openGroupInWin") {
        emit openGroupInWin(getPathsFromKey(key));
    }
    else if (name == "empty") {
        MvQ::emptyWasteBasket();
    }
}

void MvQBookmarks::command(QString name)
{
    if (name == "addEntry") {
        emit bookmarkFolder();
    }
    else if (name == "addTabs") {
        emit bookmarkTabs();
    }
    else if (name == "addBookmark") {
        auto* key = new MvKey;
        addItem(key);
    }
}

// Static
bool MvQBookmarks::addItem(MvKey* key)
{
    if (!key)
        return false;

    QDialog* dialog = nullptr;

    if (!MvQBookmarks::isFolderGroup(key))
        dialog = new MvQBookmarksDialog(key, tr("Add bookmark"));
    else
        dialog = new MvQBookmarksGroupDialog(key, tr("Add new bookmark group"));

    bool retVal = false;
    if (dialog->exec() == QDialog::Accepted) {
        model_->profileIsAboutToChange();
        prof_->addKey(key);
        model_->setKeyProfile(prof_);
        MvQBookmarks::save();

        retVal = true;
    }
    else {
        delete key;
        retVal = false;
    }

    dialog->deleteLater();
    return retVal;
}


// Static
bool MvQBookmarks::addItem(IconObject* obj)
{
    if (obj && !obj->isFolder())
        return false;

    auto* key = new MvKey;
    if (obj) {
        key->setName(obj->fullName());
        key->setShortName(obj->name());
    }

    return MvQBookmarks::addItem(key);
}

// Static
bool MvQBookmarks::addItem(QString path)
{
    if (path.isEmpty())
        return false;

    Path p = Folder::top()->path();
    Path realPath = p.add(path.toStdString());

    if (!realPath.exists())
        return false;

    auto* key = new MvKey;
    key->setName(path.toStdString());
    key->setShortName(realPath.name());

    return MvQBookmarks::addItem(key);
}

// Static
bool MvQBookmarks::addItem(QList<Folder*> folderLst)
{
    auto* key = new MvKey;
    // Foldergroup bookmarks' name maust be FOLDERGROUP !!!
    key->setName("FOLDERGROUP");
    key->setShortName("Tabs");

    // Set data for the paths
    key->setMetaData("path_count", QString::number(folderLst.count()).toStdString());
    for (int i = 0; i < folderLst.count(); i++) {
        QString id;
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
        id.asprintf("path_%02d", i);
#else
        id.sprintf("path_%02d", i);
#endif
        key->setMetaData(id.toStdString(), folderLst.at(i)->fullName());
    }

    return MvQBookmarks::addItem(key);
}

// static
bool MvQBookmarks::editItem(QString path)
{
    bool retVal = false;
    MvKeyProfile* prof = model_->profile();
    if (!prof)
        return false;

    std::string p = path.toStdString();
    for (unsigned int i = 0; i < prof->size(); i++) {
        if (prof->at(i)->name() == p) {
            retVal = editItem(prof->at(i));
        }
    }

    return retVal;
}

// static
bool MvQBookmarks::editItem(MvKey* key)
{
    if (!key)
        return false;

    bool accepted = false;
    if (key->name() == "FOLDERGROUP" && !key->metaData("path_count").empty()) {
        MvQBookmarksGroupDialog dialog(key, tr("Edit bookmark group"));
        if (dialog.exec() == QDialog::Accepted) {
            accepted = true;
        }
    }
    else {
        MvQBookmarksDialog dialog(key, tr("Edit bookmark"));
        if (dialog.exec() == QDialog::Accepted) {
            accepted = true;
        }
    }

    if (accepted) {
        // Not too efficient
        model_->profileIsAboutToChange();
        model_->setKeyProfile(prof_);
    }

    return accepted;
}


bool MvQBookmarks::editItem(const QModelIndex& index)
{
    MvKeyProfile* prof = model_->profile();
    MvKey* key = nullptr;
    if (prof && index.isValid() && index.row() <= static_cast<int>(prof->size() - 1)) {
        key = prof->at(index.row());
    }
    else
        return false;

    return MvQBookmarks::editItem(key);
}

bool MvQBookmarks::duplicateItem(const QModelIndex& index)
{
    MvKeyProfile* prof = model_->profile();
    MvKey* key = nullptr;
    if (prof && index.isValid() && index.row() <= static_cast<int>(prof->size() - 1)) {
        key = prof->at(index.row());
    }
    else
        return false;

    MvKey* dupKey = key->clone();
    if (!dupKey->shortName().empty()) {
        model_->profileIsAboutToChange();
        prof->addKey(dupKey);
        model_->setKeyProfile(prof);
        return true;
    }

    return false;
}

bool MvQBookmarks::deleteItem(const QModelIndex& index)
{
    MvKeyProfile* prof = model_->profile();
    if (prof == nullptr || !index.isValid())
        return false;

    MvKey* key = prof->at(index.row());

    QString str = tr("Are you sure that you want to delete entry <b>");
    str += QString::fromStdString(key->shortName());
    str += "</b>?";

    QMessageBox msgBox;
    msgBox.setWindowTitle(tr("Delete bookmark"));
    msgBox.setText(str);
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Cancel);

    int ret = msgBox.exec();

    switch (ret) {
        case QMessageBox::Yes: {
            model_->profileIsAboutToChange();
            prof->deleteKey(index.row());
            model_->setKeyProfile(prof);
            return true;
        } break;
        case QMessageBox::Cancel:
            // Cancel was clicked
            break;
        default:
            // should never be reached
            break;
    }

    return false;
}

MvKey* MvQBookmarks::getKey(const QModelIndex& index)
{
    if (index.row() >= 0) {
        MvKeyProfile* prof = model_->profile();
        if (prof && index.row() <= static_cast<int>(prof->size() - 1)) {
            return prof->at(index.row());
        }
    }

    return nullptr;
}

QString MvQBookmarks::getPath(const QModelIndex& index)
{
    MvKey* key = getKey(index);
    return (key) ? QString::fromStdString(key->name()) : QString();
}

QStringList MvQBookmarks::getPathsFromKey(MvKey* key)
{
    QStringList lst;

    if (!key)
        return lst;

    std::string cntStr = key->metaData("path_count");
    if (!cntStr.empty()) {
        int cnt = QString::fromStdString(cntStr).toInt();
        for (int i = 0; i < cnt; i++) {
            QString id;
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
            id.asprintf("path_%02d", i);
#else
            id.sprintf("path_%02d", i);
#endif
            std::string val = key->metaData(id.toStdString());
            if (!val.empty())
                lst << QString::fromStdString(val);
        }
    }

    return lst;
}

// Static
bool MvQBookmarks::isFolderGroup(MvKey* key)
{
    if (!key)
        return false;

    return (key->name() == "FOLDERGROUP" && key->metaData("path_count").empty() == false);
}


//================================================
//
//  MvQBookmarksMenu
//
//================================================

MvQBookmarksMenu::MvQBookmarksMenu(QWidget* parent, QMenu* menu) :
    MvQBookmarks(parent),
    menu_(menu)
{
    actionFolder_ = new QAction(menu_);
    actionFolder_->setText(tr("Bookmark current &folder"));
    // actionFolder_->setShortcut(tr("Ctrl+D"));
    menu_->addAction(actionFolder_);

    actionTabs_ = new QAction(menu_);
    actionTabs_->setText(tr("Bookmark current &tabs"));
    // actionTabs_->setShortcut(tr("Ctrl+T"));
    menu_->addAction(actionTabs_);

    auto* sep1 = new QAction(this);
    sep1->setSeparator(true);
    menu_->addAction(sep1);

    actionAdd_ = new QAction(menu_);
    actionAdd_->setText(tr("New bookmark"));
    // addAction->setShortcut(tr("Ctrl+T"));
    menu_->addAction(actionAdd_);

    auto* sep = new QAction(this);
    sep->setSeparator(true);
    menu_->addAction(sep);

    // Populate
    slotUpdate();

    connect(model_, SIGNAL(modelReset()),
            this, SLOT(slotUpdate()));

    connect(menu_, SIGNAL(triggered(QAction*)),
            this, SLOT(slotMenu(QAction*)));

    // Context menu
    menu_->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(menu_, SIGNAL(customContextMenuRequested(const QPoint&)),
            this, SLOT(slotContextMenu(const QPoint&)));
}

void MvQBookmarksMenu::slotContextMenu(const QPoint& pos)
{
    MvQContextItemSet* cms = cmSet();
    if (!cms)
        return;

    QAction* ac = menu_->actionAt(pos);
    QString path = "path=" + getPath(ac);

    if (!path.isEmpty()) {
        QString selection = MvQContextMenu::instance()->exec(cms->icon(), menu_->mapToGlobal(pos), menu_,
                                                             " ", path);
        if (!selection.isEmpty()) {
            QModelIndex index = getIndex(ac);
            command(selection, index);
        }
    }
}
void MvQBookmarksMenu::slotUpdate()
{
    QList<QAction*> lst = menu_->actions();

    int cnt = model_->rowCount();

    for (int i = 0; i < cnt; i++) {
        QAction* action = nullptr;
        if (lst.count() <= i + 5) {
            action = new QAction(menu_);
            menu_->addAction(action);
        }
        else {
            action = lst.at(i + 5);
        }

        QModelIndex index = model_->index(i, 0);
        QString name = model_->data(index, Qt::DisplayRole).toString();
        QString tooltip = model_->data(index, Qt::ToolTipRole).toString();
        auto pix = model_->data(index, Qt::DecorationRole).value<QPixmap>();

        action->setText(name);
        action->setToolTip(tooltip);
        action->setIcon(pix);
        action->setData(i + 1);
    }

    while (lst.count() > cnt + 5) {
        QAction* action = lst.takeLast();
        menu_->removeAction(action);
        delete action;
    }
}

void MvQBookmarksMenu::slotMenu(QAction* ac)
{
    if (ac == actionFolder_)
        command("addEntry");
    else if (ac == actionTabs_)
        command("addTabs");
    else if (ac == actionAdd_)
        command("addBookmark");
    else
        defaultCommand(getIndex(ac));
}

QString MvQBookmarksMenu::getPath(QAction* ac)
{
    if (ac && !ac->isSeparator()) {
        QModelIndex index = getIndex(ac);
        return MvQBookmarks::getPath(index);
    }

    return {};
}

MvKey* MvQBookmarksMenu::getKey(QAction* ac)
{
    if (ac && !ac->isSeparator()) {
        QModelIndex index = getIndex(ac);
        return MvQBookmarks::getKey(index);
    }

    return nullptr;
}

QModelIndex MvQBookmarksMenu::getIndex(QAction* ac)
{
    if (ac && !ac->isSeparator()) {
        int i = ac->data().toInt() - 1;
        return model_->index(i, 0);
    }

    return {};
}

//================================================
//
//  MvQBookmarksView
//
//================================================

MvQBookmarksView::MvQBookmarksView(QWidget* parent) :
    QListView(parent)
{
    setDragEnabled(true);
    setAcceptDrops(true);

    setSpacing(1);
    setProperty("bookmarkView", "true");
}


void MvQBookmarksView::checkDropTarget(QDropEvent* event)
{
    if (!event->mimeData()->hasFormat("metview/icon")) {
        removeDropTarget();
    }

    auto index = indexAt(MvQ::eventPos(event));
    auto s = model()->data(index, Qt::UserRole).toString();

    if (!s.isEmpty()) {
        Folder* f = Folder::folder(s.toStdString(), false);
        if (f && !f->locked()) {
            Qt::DropAction dropAction = event->proposedAction();
            MvQDropTarget::Instance()->reset(QString::fromStdString(f->name()),
                                             (dropAction == Qt::MoveAction), "folder");

            if (window()) {
                MvQDropTarget::Instance()->move(mapToGlobal(MvQ::eventPos(event)) + QPoint(20, 20));
            }
            return;
        }
    }

    removeDropTarget();
}

void MvQBookmarksView::removeDropTarget()
{
    MvQDropTarget::Instance()->hide();
}

void MvQBookmarksView::dragEnterEvent(QDragEnterEvent* event)
{
    if (event->source() != this) {
        if (event->source() &&
            (event->proposedAction() == Qt::CopyAction ||
             event->proposedAction() == Qt::MoveAction)) {
            event->accept();
        }
        else
            event->ignore();
    }
    else
        QListView::dragEnterEvent(event);
}

void MvQBookmarksView::dragMoveEvent(QDragMoveEvent* event)
{
    if (event->source() != this) {
        if (event->source() &&
            (event->proposedAction() == Qt::CopyAction ||
             event->proposedAction() == Qt::MoveAction)) {
            checkDropTarget(event);
            event->accept();
        }
        else {
            removeDropTarget();
            event->ignore();
        }
    }
    else
        QListView::dragMoveEvent(event);
}

void MvQBookmarksView::dragLeaveEvent(QDragLeaveEvent* event)
{
    removeDropTarget();
    event->accept();
}

void MvQBookmarksView::dropEvent(QDropEvent* event)
{
    if (event->source() != this) {
        removeDropTarget();

        if (!event->source()) {
            event->ignore();
            return;
        }

        if (event->proposedAction() != Qt::CopyAction &&
            event->proposedAction() != Qt::MoveAction) {
            event->ignore();
            return;
        }

        auto index = indexAt(MvQ::eventPos(event));
        QString s = model()->data(index, Qt::UserRole).toString();

        if (!s.isEmpty()) {
            Folder* f = Folder::folder(s.toStdString(), false);
            MvQFolderViewBase::dropToFolder(f, event);
        }
    }

    else
        QListView::dropEvent(event);
}

//================================================
//
//  MvQBookmarksPanel
//
//================================================

MvQBookmarksPanel::MvQBookmarksPanel(QWidget* parent) :
    MvQBookmarks(parent)
{
    widget_ = new QWidget(parent);

    auto* vb = new QVBoxLayout;
    vb->setSpacing(0);
    vb->setContentsMargins(0, 0, 0, 0);
    widget_->setLayout(vb);

    auto* hb = new QHBoxLayout;
    vb->addLayout(hb);

    hb->addSpacing(4);

    auto* label = new QLabel("<b>" + tr("Bookmarks") + "</b>", widget_);
    hb->addWidget(label);

    auto* closeTb = new QToolButton(widget_);
    closeTb->setAutoRaise(true);
    closeTb->setIcon(QPixmap(":/desktop/close_grey.svg"));
    closeTb->setToolTip(tr("Close sidebar"));
    hb->addWidget(closeTb);

    connect(closeTb, SIGNAL(clicked(bool)),
            this, SIGNAL(closePanel(bool)));

    view_ = new MvQBookmarksView(widget_);
    vb->addWidget(view_);

    view_->setModel(model_);
    view_->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(view_, SIGNAL(doubleClicked(const QModelIndex&)),
            this, SLOT(slotDoubleClickItem(const QModelIndex&)));

    // Context menu
    connect(view_, SIGNAL(customContextMenuRequested(const QPoint&)),
            this, SLOT(slotContextMenu(const QPoint&)));
}

void MvQBookmarksPanel::slotDoubleClickItem(const QModelIndex& index)
{
    defaultCommand(index);
}

void MvQBookmarksPanel::slotContextMenu(const QPoint& pos)
{
    MvQContextItemSet* cms = cmSet();
    if (!cms)
        return;

    QModelIndex index = view_->indexAt(pos);

    // Desktop action
    if (!index.isValid()) {
        QString selection = MvQContextMenu::instance()->exec(cms->desktop(), view_->mapToGlobal(pos), view_);
        if (!selection.isEmpty())
            command(selection);
    }

    // Icon Actions
    else if (model_->profile() && index.isValid()) {
        QString path = "path=" + getPath(index);
        QString selection = MvQContextMenu::instance()->exec(cms->icon(), view_->mapToGlobal(pos), view_,
                                                             "lookupOrOpenInTab", path);

        if (!selection.isEmpty())
            command(selection, index);
    }
}

void MvQBookmarksPanel::slotAddItem(bool)
{
    command("addEntry");
}


//================================================
//
//  MvQBookmarksDialog
//
//================================================

MvQBookmarksDialog::MvQBookmarksDialog(MvKey* key, QString title, QWidget* parent) :
    QDialog(parent),
    key_(key)
{
    setWindowTitle(title);

    auto* vb = new QVBoxLayout;
    setLayout(vb);

    auto* grid = new QGridLayout;
    vb->addLayout(grid);

    auto* label = new QLabel(tr("&Label:"));
    labelEdit_ = new QLineEdit;
    label->setBuddy(labelEdit_);
    if (key_) {
        labelEdit_->setText(QString::fromStdString(key_->shortName()));
    }

    grid->addWidget(label, 0, 0);
    grid->addWidget(labelEdit_, 0, 1);

    label = new QLabel(tr("&Path:"));
    pathEdit_ = new QLineEdit;
    label->setBuddy(pathEdit_);
    if (key_) {
        pathEdit_->setText(QString::fromStdString(key_->name()));
    }
    grid->addWidget(label, 1, 0);
    grid->addWidget(pathEdit_, 1, 1);

    // Buttonbox
    auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    // Try to find the optimal dialog width
    QFont font;
    QFontMetrics fm(font);
    setMinimumWidth(MvQ::textWidth(fm, tr("Label")) + MvQ::textWidth(fm, pathEdit_->text()) + 100);

    vb->addWidget(buttonBox);
}

void MvQBookmarksDialog::accept()
{
    QString path = pathEdit_->text();
    QString label = labelEdit_->text();

    QString errTxt = tr("Failed to create bookmark!");

    if (path.isEmpty()) {
        QMessageBox::critical(this, tr("Create bookmark"), errTxt + tr("<b> Path</b> cannot be empty!"));
        return;
    }
    else if (label.isEmpty()) {
        QMessageBox::critical(this, tr("Create bookmark"), errTxt + tr(" <b>Label</b> cannot be empty!"));
        return;
    }

    if (key_) {
        key_->setName(path.toStdString());
        key_->setShortName(label.toStdString());
    }

    QDialog::accept();
}

//================================================
//
//  MvQBookmarksGroupDialog
//
//================================================

MvQBookmarksGroupDialog::MvQBookmarksGroupDialog(MvKey* key, QString title, QWidget* parent) :
    QDialog(parent),
    key_(key)
{
    setWindowTitle(title);

    auto* vb = new QVBoxLayout;
    setLayout(vb);

    auto* grid = new QGridLayout;
    vb->addLayout(grid);

    auto* label = new QLabel(tr("&Label:"));
    labelEdit_ = new QLineEdit;
    label->setBuddy(labelEdit_);
    if (key_) {
        labelEdit_->setText(QString::fromStdString(key_->shortName()));
    }

    grid->addWidget(label, 0, 0);
    grid->addWidget(labelEdit_, 0, 1);

    label = new QLabel(tr("&Paths:"));
    pathEdit_ = new QPlainTextEdit;
    label->setBuddy(pathEdit_);
    pathEdit_->setPlainText(getPathsFromKey());

    grid->addWidget(label, 1, 0);
    grid->addWidget(pathEdit_, 1, 1);

    // Buttonbox
    auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);

    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    vb->addWidget(buttonBox);
}

QString MvQBookmarksGroupDialog::getPathsFromKey()
{
    QString str;

    if (!key_)
        return str;

    std::string cntStr = key_->metaData("path_count");
    if (!cntStr.empty()) {
        int cnt = QString::fromStdString(cntStr).toInt();
        for (int i = 0; i < cnt; i++) {
            QString id;
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
            id.asprintf("path_%02d", i);
#else
            id.sprintf("path_%02d", i);
#endif
            std::string val = key_->metaData(id.toStdString());
            if (!val.empty())
                str += QString::fromStdString(val) + "\n";
        }
    }

    return str;
}

void MvQBookmarksGroupDialog::accept()
{
    QString path = pathEdit_->toPlainText();
    QString label = labelEdit_->text();

    QString errTxt = tr("Failed to create bookmark!");

    if (path.isEmpty()) {
        QMessageBox::critical(this, tr("Create bookmark"), errTxt + tr(" <b>Path</b> cannot be empty!"));
        return;
    }
    else if (label.isEmpty()) {
        QMessageBox::critical(this, tr("Create bookmark"), errTxt + tr(" <b>Label</b> cannot be empty!"));
        return;
    }

    if (key_) {
        // key_->setName(labelEdit_->text().toStdString());
        key_->setShortName(label.toStdString());

        // Figure out paths and add it to the key's metadata
        key_->clearMetaData();
        QStringList lst = path.split("\n");
        int cnt = 0;
        foreach (QString s, lst) {
            QString p = s.simplified();
            if (!p.isEmpty()) {
                QString id;
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
                id.asprintf("path_%02d", cnt);
#else
                id.sprintf("path_%02d", cnt);
#endif
                key_->setMetaData(id.toStdString(), p.toStdString());
                cnt++;
            }
        }
        key_->setMetaData("path_count", QString::number(cnt).toStdString());
    }
    QDialog::accept();
}
