File indexing completed on 2024-03-24 17:24:43

0001 /**
0002  * SPDX-FileCopyrightText: (C) 2005 Sébastien Laoût <slaout@linux62.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "tagsedit.h"
0008 
0009 #include <QAction>
0010 #include <QApplication>
0011 #include <QCheckBox>
0012 #include <QDialogButtonBox>
0013 #include <QFontComboBox>
0014 #include <QGridLayout>
0015 #include <QGroupBox>
0016 #include <QHBoxLayout>
0017 #include <QHeaderView> //For m_tags->header()
0018 #include <QLabel>
0019 #include <QLineEdit>
0020 #include <QLocale>
0021 #include <QPushButton>
0022 #include <QVBoxLayout>
0023 #include <QtCore/QEvent>
0024 #include <QtCore/QList>
0025 #include <QtCore/QTimer>
0026 #include <QtGui/QKeyEvent>
0027 #include <QtGui/QMouseEvent>
0028 #include <QtGui/QPainter>
0029 
0030 #include <KConfigGroup>
0031 #include <KIconButton>
0032 #include <KIconLoader>
0033 #include <KLocalizedString>
0034 #include <KMessageBox>
0035 #include <KSeparator>
0036 #include <KShortcutWidget>
0037 
0038 #include "bnpview.h"
0039 #include "global.h"
0040 #include "kcolorcombo2.h"
0041 #include "tag.h"
0042 #include "variouswidgets.h" //For FontSizeCombo
0043 
0044 /** class StateCopy: */
0045 
0046 StateCopy::StateCopy(State *old /* = 0*/)
0047 {
0048     oldState = old;
0049     newState = new State();
0050     if (oldState)
0051         oldState->copyTo(newState);
0052 }
0053 
0054 StateCopy::~StateCopy()
0055 {
0056     delete newState;
0057 }
0058 
0059 void StateCopy::copyBack()
0060 {
0061 }
0062 
0063 /** class TagCopy: */
0064 
0065 TagCopy::TagCopy(Tag *old /* = 0*/)
0066 {
0067     oldTag = old;
0068     newTag = new Tag();
0069     if (oldTag)
0070         oldTag->copyTo(newTag);
0071 
0072     if (old)
0073         for (State::List::iterator it = old->states().begin(); it != old->states().end(); ++it)
0074             stateCopies.append(new StateCopy(*it));
0075     else
0076         stateCopies.append(new StateCopy());
0077 }
0078 
0079 TagCopy::~TagCopy()
0080 {
0081     delete newTag;
0082 }
0083 
0084 void TagCopy::copyBack()
0085 {
0086 }
0087 
0088 bool TagCopy::isMultiState()
0089 {
0090     return (stateCopies.count() > 1);
0091 }
0092 
0093 /** class TagListViewItem: */
0094 
0095 TagListViewItem::TagListViewItem(QTreeWidget *parent, TagCopy *tagCopy)
0096     : QTreeWidgetItem(parent)
0097     , m_tagCopy(tagCopy)
0098     , m_stateCopy(nullptr)
0099 {
0100     setText(0, tagCopy->newTag->name());
0101 }
0102 
0103 TagListViewItem::TagListViewItem(QTreeWidgetItem *parent, TagCopy *tagCopy)
0104     : QTreeWidgetItem(parent)
0105     , m_tagCopy(tagCopy)
0106     , m_stateCopy(nullptr)
0107 {
0108     setText(0, tagCopy->newTag->name());
0109 }
0110 
0111 TagListViewItem::TagListViewItem(QTreeWidget *parent, QTreeWidgetItem *after, TagCopy *tagCopy)
0112     : QTreeWidgetItem(parent, after)
0113     , m_tagCopy(tagCopy)
0114     , m_stateCopy(nullptr)
0115 {
0116     setText(0, tagCopy->newTag->name());
0117 }
0118 
0119 TagListViewItem::TagListViewItem(QTreeWidgetItem *parent, QTreeWidgetItem *after, TagCopy *tagCopy)
0120     : QTreeWidgetItem(parent, after)
0121     , m_tagCopy(tagCopy)
0122     , m_stateCopy(nullptr)
0123 {
0124     setText(0, tagCopy->newTag->name());
0125 }
0126 
0127 /* */
0128 
0129 TagListViewItem::TagListViewItem(QTreeWidget *parent, StateCopy *stateCopy)
0130     : QTreeWidgetItem(parent)
0131     , m_tagCopy(nullptr)
0132     , m_stateCopy(stateCopy)
0133 {
0134     setText(0, stateCopy->newState->name());
0135 }
0136 
0137 TagListViewItem::TagListViewItem(QTreeWidgetItem *parent, StateCopy *stateCopy)
0138     : QTreeWidgetItem(parent)
0139     , m_tagCopy(nullptr)
0140     , m_stateCopy(stateCopy)
0141 {
0142     setText(0, stateCopy->newState->name());
0143 }
0144 
0145 TagListViewItem::TagListViewItem(QTreeWidget *parent, QTreeWidgetItem *after, StateCopy *stateCopy)
0146     : QTreeWidgetItem(parent, after)
0147     , m_tagCopy(nullptr)
0148     , m_stateCopy(stateCopy)
0149 {
0150     setText(0, stateCopy->newState->name());
0151 }
0152 
0153 TagListViewItem::TagListViewItem(QTreeWidgetItem *parent, QTreeWidgetItem *after, StateCopy *stateCopy)
0154     : QTreeWidgetItem(parent, after)
0155     , m_tagCopy(nullptr)
0156     , m_stateCopy(stateCopy)
0157 {
0158     setText(0, stateCopy->newState->name());
0159 }
0160 
0161 /* */
0162 
0163 TagListViewItem::~TagListViewItem()
0164 {
0165 }
0166 
0167 TagListViewItem *TagListViewItem::lastChild()
0168 {
0169     if (childCount() <= 0)
0170         return nullptr;
0171     return (TagListViewItem *)child(childCount() - 1);
0172 }
0173 
0174 bool TagListViewItem::isEmblemObligatory()
0175 {
0176     return m_stateCopy != nullptr; // It's a state of a multi-state
0177 }
0178 
0179 TagListViewItem *TagListViewItem::prevSibling()
0180 {
0181     TagListViewItem *item = this;
0182     int idx = 0;
0183     if (!parent()) {
0184         idx = treeWidget()->indexOfTopLevelItem(item);
0185         if (idx <= 0)
0186             return nullptr;
0187         return (TagListViewItem *)treeWidget()->topLevelItem(idx - 1);
0188     } else {
0189         idx = parent()->indexOfChild(item);
0190         if (idx <= 0)
0191             return nullptr;
0192         return (TagListViewItem *)parent()->child(idx - 1);
0193     }
0194 }
0195 
0196 TagListViewItem *TagListViewItem::nextSibling()
0197 {
0198     TagListViewItem *item = this;
0199     int idx = 0;
0200     if (!parent()) {
0201         idx = treeWidget()->indexOfTopLevelItem(item);
0202         if (idx >= treeWidget()->topLevelItemCount())
0203             return nullptr;
0204         return (TagListViewItem *)treeWidget()->topLevelItem(idx + 1);
0205     } else {
0206         idx = parent()->indexOfChild(item);
0207         if (idx >= parent()->childCount())
0208             return nullptr;
0209         return (TagListViewItem *)parent()->child(idx + 1);
0210     }
0211 }
0212 
0213 TagListViewItem *TagListViewItem::parent() const
0214 {
0215     return (TagListViewItem *)QTreeWidgetItem::parent();
0216 }
0217 
0218 // TODO: TagListViewItem::
0219 int TAG_ICON_SIZE = 16;
0220 int TAG_MARGIN = 1;
0221 
0222 int TagListViewItem::width(const QFontMetrics & /* fontMetrics */, const QTreeWidget * /*listView*/, int /* column */) const
0223 {
0224     return treeWidget()->width();
0225 }
0226 
0227 void TagListViewItem::setup()
0228 {
0229     QString text = (m_tagCopy ? m_tagCopy->newTag->name() : m_stateCopy->newState->name());
0230     State *state = (m_tagCopy ? m_tagCopy->stateCopies[0]->newState : m_stateCopy->newState);
0231 
0232     QFont font = state->font(treeWidget()->font());
0233 
0234     setText(0, text);
0235 
0236     QBrush brush;
0237 
0238     bool withIcon = m_stateCopy || (m_tagCopy && !m_tagCopy->isMultiState());
0239     brush.setColor(isSelected() ? qApp->palette().color(QPalette::Highlight)
0240                                 : (withIcon && state->backgroundColor().isValid() ? state->backgroundColor() : treeWidget()->viewport()->palette().color(treeWidget()->viewport()->backgroundRole())));
0241     setBackground(1, brush);
0242 }
0243 
0244 /** class TagListView: */
0245 
0246 TagListView::TagListView(QWidget *parent)
0247     : QTreeWidget(parent)
0248 {
0249     setItemDelegate(new TagListDelegate);
0250 }
0251 
0252 TagListView::~TagListView()
0253 {
0254 }
0255 
0256 void TagListView::keyPressEvent(QKeyEvent *event)
0257 {
0258     if (event->key() == Qt::Key_Delete)
0259         Q_EMIT deletePressed();
0260     else if (event->key() != Qt::Key_Left || (currentItem() && currentItem()->parent()))
0261         // Do not allow to open/close first-level items
0262         QTreeWidget::keyPressEvent(event);
0263 }
0264 
0265 void TagListView::mouseDoubleClickEvent(QMouseEvent *event)
0266 {
0267     // Ignore this event! Do not open/close first-level items!
0268 
0269     // But trigger edit (change focus to name) when double-click an item:
0270     if (itemAt(event->pos()) != nullptr)
0271         Q_EMIT doubleClickedItem();
0272 }
0273 
0274 void TagListView::mousePressEvent(QMouseEvent *event)
0275 {
0276     // When clicking on an empty space, QListView would unselect the current item! We forbid that!
0277     if (itemAt(event->pos()) != nullptr)
0278         QTreeWidget::mousePressEvent(event);
0279 }
0280 
0281 void TagListView::mouseReleaseEvent(QMouseEvent *event)
0282 {
0283     // When clicking on an empty space, QListView would unselect the current item! We forbid that!
0284     if (itemAt(event->pos()) != nullptr)
0285         QTreeWidget::mouseReleaseEvent(event);
0286 }
0287 
0288 TagListViewItem *TagListView::currentItem() const
0289 {
0290     return (TagListViewItem *)QTreeWidget::currentItem();
0291 }
0292 
0293 TagListViewItem *TagListView::firstChild() const
0294 {
0295     if (topLevelItemCount() <= 0)
0296         return nullptr;
0297     return (TagListViewItem *)topLevelItem(0);
0298 }
0299 
0300 TagListViewItem *TagListView::lastItem() const
0301 {
0302     if (topLevelItemCount() <= 0)
0303         return nullptr;
0304     return (TagListViewItem *)topLevelItem(topLevelItemCount() - 1);
0305 }
0306 
0307 /** class TagsEditDialog: */
0308 
0309 TagsEditDialog::TagsEditDialog(QWidget *parent, State *stateToEdit, bool addNewTag)
0310     : QDialog(parent)
0311     , m_loading(false)
0312 {
0313     // QDialog options
0314     setWindowTitle(i18n("Customize Tags"));
0315     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0316     QWidget *mainWidget = new QWidget(this);
0317     QVBoxLayout *mainLayout = new QVBoxLayout;
0318     setLayout(mainLayout);
0319     mainLayout->addWidget(mainWidget);
0320     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0321     okButton->setDefault(true);
0322     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0323     connect(buttonBox, &QDialogButtonBox::accepted, this, &TagsEditDialog::accept);
0324     connect(buttonBox, &QDialogButtonBox::rejected, this, &TagsEditDialog::reject);
0325     mainLayout->addWidget(buttonBox);
0326     okButton->setDefault(true);
0327     setObjectName("CustomizeTags");
0328 
0329     QHBoxLayout *layout = new QHBoxLayout(mainWidget);
0330 
0331     /* Left part: */
0332 
0333     QPushButton *newTag = new QPushButton(i18n("Ne&w Tag"), mainWidget);
0334     QPushButton *newState = new QPushButton(i18n("New St&ate"), mainWidget);
0335 
0336     connect(newTag, &QPushButton::clicked, this, &TagsEditDialog::newTag);
0337     connect(newState, &QPushButton::clicked, this, &TagsEditDialog::newState);
0338 
0339     m_tags = new TagListView(mainWidget);
0340     m_tags->header()->hide();
0341     m_tags->setRootIsDecorated(false);
0342     // m_tags->addColumn(QString());
0343     // m_tags->setSorting(-1); // Sort column -1, so disabled sorting
0344     // m_tags->setResizeMode(QTreeWidget::LastColumn);
0345 
0346     m_tags->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0347 
0348     m_moveUp = new QPushButton(mainWidget);
0349     KGuiItem::assign(m_moveUp, KGuiItem(QString(), "arrow-up"));
0350     m_moveDown = new QPushButton(mainWidget);
0351     KGuiItem::assign(m_moveDown, KGuiItem(QString(), "arrow-down"));
0352     m_deleteTag = new QPushButton(mainWidget);
0353     KGuiItem::assign(m_deleteTag, KGuiItem(QString(), "edit-delete"));
0354 
0355     m_moveUp->setToolTip(i18n("Move Up (Ctrl+Shift+Up)"));
0356     m_moveDown->setToolTip(i18n("Move Down (Ctrl+Shift+Down)"));
0357     m_deleteTag->setToolTip(i18n("Delete"));
0358 
0359     connect(m_moveUp, &QPushButton::clicked, this, &TagsEditDialog::moveUp);
0360     connect(m_moveDown, &QPushButton::clicked, this, &TagsEditDialog::moveDown);
0361     connect(m_deleteTag, &QPushButton::clicked, this, &TagsEditDialog::deleteTag);
0362 
0363     QHBoxLayout *topLeftLayout = new QHBoxLayout;
0364     topLeftLayout->addWidget(m_moveUp);
0365     topLeftLayout->addWidget(m_moveDown);
0366     topLeftLayout->addWidget(m_deleteTag);
0367 
0368     QVBoxLayout *leftLayout = new QVBoxLayout;
0369     leftLayout->addWidget(newTag);
0370     leftLayout->addWidget(newState);
0371     leftLayout->addWidget(m_tags);
0372     leftLayout->addLayout(topLeftLayout);
0373 
0374     layout->addLayout(leftLayout);
0375 
0376     /* Right part: */
0377 
0378     QWidget *rightWidget = new QWidget(mainWidget);
0379 
0380     m_tagBox = new QGroupBox(i18n("Tag"), rightWidget);
0381     m_tagBoxLayout = new QHBoxLayout;
0382     m_tagBox->setLayout(m_tagBoxLayout);
0383 
0384     QWidget *tagWidget = new QWidget;
0385     m_tagBoxLayout->addWidget(tagWidget);
0386 
0387     m_tagName = new QLineEdit(tagWidget);
0388     QLabel *tagNameLabel = new QLabel(i18n("&Name:"), tagWidget);
0389     tagNameLabel->setBuddy(m_tagName);
0390 
0391     m_shortcut = new KShortcutWidget(tagWidget);
0392     m_removeShortcut = new QPushButton(i18nc("Remove tag shortcut", "&Remove"), tagWidget);
0393     QLabel *shortcutLabel = new QLabel(i18n("S&hortcut:"), tagWidget);
0394     shortcutLabel->setBuddy(m_shortcut);
0395     //connect(m_shortcut, &KShortcutWidget::shortcutChanged, this, &TagsEditDialog::capturedShortcut);
0396     connect(m_removeShortcut, &QPushButton::clicked, this, &TagsEditDialog::removeShortcut);
0397 
0398     m_inherit = new QCheckBox(i18n("&Inherited by new sibling notes"), tagWidget);
0399 
0400     m_allowCrossRefernce = new QCheckBox(i18n("Allow Cross Reference Links"), tagWidget);
0401 
0402     HelpLabel *allowCrossReferenceHelp = new HelpLabel(i18n("What does this do?"),
0403         "<p>" + i18n("This option will enable you to type a cross reference link directly into a text note. Cross Reference links can have the following syntax:") + "</p>" + "<p>" +
0404         i18n("From the top of the tree (Absolute path):") + "<br />" + i18n("[[/top level item/child|optional title]]") + "<p>" + "<p>" + i18n("Relative to the current basket:") +
0405         "<br />" + i18n("[[../sibling|optional title]]") + "<br />" + i18n("[[child|optional title]]") + "<br />" + i18n("[[./child|optional title]]") + "<p>"+
0406         "<p>" +i18n("Baskets matching is cAse inSEnsItive.") + "</p>",
0407         tagWidget);
0408 
0409     QGridLayout *tagGrid = new QGridLayout(tagWidget);
0410     tagGrid->addWidget(tagNameLabel, 0, 0);
0411     tagGrid->addWidget(m_tagName, 0, 1, 1, 3);
0412     tagGrid->addWidget(shortcutLabel, 1, 0);
0413     tagGrid->addWidget(m_shortcut, 1, 1);
0414     tagGrid->addWidget(m_removeShortcut, 1, 2);
0415     tagGrid->addWidget(m_inherit, 2, 0, 1, 4);
0416     tagGrid->addWidget(m_allowCrossRefernce, 3, 0);
0417     tagGrid->addWidget(allowCrossReferenceHelp, 3, 1);
0418     tagGrid->setColumnStretch(/*col=*/3, /*stretch=*/255);
0419 
0420     m_stateBox = new QGroupBox(i18n("State"), rightWidget);
0421     m_stateBoxLayout = new QHBoxLayout;
0422     m_stateBox->setLayout(m_stateBoxLayout);
0423 
0424     QWidget *stateWidget = new QWidget;
0425     m_stateBoxLayout->addWidget(stateWidget);
0426 
0427     m_stateName = new QLineEdit(stateWidget);
0428     m_stateNameLabel = new QLabel(i18n("Na&me:"), stateWidget);
0429     m_stateNameLabel->setBuddy(m_stateName);
0430 
0431     QWidget *emblemWidget = new QWidget(stateWidget);
0432     m_emblem = new KIconButton(emblemWidget);
0433     m_emblem->setIconType(KIconLoader::NoGroup, KIconLoader::Action);
0434     m_emblem->setIconSize(16);
0435     m_emblem->setIcon("edit-delete");
0436     m_removeEmblem = new QPushButton(i18nc("Remove tag emblem", "Remo&ve"), emblemWidget);
0437     QLabel *emblemLabel = new QLabel(i18n("&Emblem:"), stateWidget);
0438     emblemLabel->setBuddy(m_emblem);
0439     connect(m_removeEmblem, &QPushButton::clicked, this, &TagsEditDialog::removeEmblem); // m_emblem.resetIcon() is not a slot!
0440 
0441     // Make the icon button and the remove button the same height:
0442     int height = qMax(m_emblem->sizeHint().width(), m_emblem->sizeHint().height());
0443     height = qMax(height, m_removeEmblem->sizeHint().height());
0444     m_emblem->setFixedSize(height, height); // Make it square
0445     m_removeEmblem->setFixedHeight(height);
0446     m_emblem->resetIcon();
0447 
0448     QHBoxLayout *emblemLayout = new QHBoxLayout(emblemWidget);
0449     emblemLayout->addWidget(m_emblem);
0450     emblemLayout->addWidget(m_removeEmblem);
0451     emblemLayout->addStretch();
0452 
0453     m_backgroundColor = new KColorCombo2(QColor(), palette().color(QPalette::Base), stateWidget);
0454     QLabel *backgroundColorLabel = new QLabel(i18n("&Background:"), stateWidget);
0455     backgroundColorLabel->setBuddy(m_backgroundColor);
0456 
0457     QHBoxLayout *backgroundColorLayout = new QHBoxLayout(nullptr);
0458     backgroundColorLayout->addWidget(m_backgroundColor);
0459     backgroundColorLayout->addStretch();
0460 
0461     QIcon boldIconSet = QIcon::fromTheme("format-text-bold");
0462     m_bold = new QPushButton(boldIconSet, QString(), stateWidget);
0463     m_bold->setCheckable(true);
0464     int size = qMax(m_bold->sizeHint().width(), m_bold->sizeHint().height());
0465     m_bold->setFixedSize(size, size); // Make it square!
0466     m_bold->setToolTip(i18n("Bold"));
0467 
0468     QIcon underlineIconSet = QIcon::fromTheme("format-text-underline");
0469     m_underline = new QPushButton(underlineIconSet, QString(), stateWidget);
0470     m_underline->setCheckable(true);
0471     m_underline->setFixedSize(size, size); // Make it square!
0472     m_underline->setToolTip(i18n("Underline"));
0473 
0474     QIcon italicIconSet = QIcon::fromTheme("format-text-italic");
0475     m_italic = new QPushButton(italicIconSet, QString(), stateWidget);
0476     m_italic->setCheckable(true);
0477     m_italic->setFixedSize(size, size); // Make it square!
0478     m_italic->setToolTip(i18n("Italic"));
0479 
0480     QIcon strikeIconSet = QIcon::fromTheme("format-text-strikethrough");
0481     m_strike = new QPushButton(strikeIconSet, QString(), stateWidget);
0482     m_strike->setCheckable(true);
0483     m_strike->setFixedSize(size, size); // Make it square!
0484     m_strike->setToolTip(i18n("Strike Through"));
0485 
0486     QLabel *textLabel = new QLabel(i18n("&Text:"), stateWidget);
0487     textLabel->setBuddy(m_bold);
0488 
0489     QHBoxLayout *textLayout = new QHBoxLayout;
0490     textLayout->addWidget(m_bold);
0491     textLayout->addWidget(m_underline);
0492     textLayout->addWidget(m_italic);
0493     textLayout->addWidget(m_strike);
0494     textLayout->addStretch();
0495 
0496     m_textColor = new KColorCombo2(QColor(), palette().color(QPalette::Text), stateWidget);
0497     QLabel *textColorLabel = new QLabel(i18n("Co&lor:"), stateWidget);
0498     textColorLabel->setBuddy(m_textColor);
0499 
0500     m_font = new QFontComboBox(stateWidget);
0501     m_font->addItem(i18n("(Default)"), 0);
0502     QLabel *fontLabel = new QLabel(i18n("&Font:"), stateWidget);
0503     fontLabel->setBuddy(m_font);
0504 
0505     m_fontSize = new FontSizeCombo(/*rw=*/true, /*withDefault=*/true, stateWidget);
0506     QLabel *fontSizeLabel = new QLabel(i18n("&Size:"), stateWidget);
0507     fontSizeLabel->setBuddy(m_fontSize);
0508 
0509     m_textEquivalent = new QLineEdit(stateWidget);
0510     QLabel *textEquivalentLabel = new QLabel(i18n("Te&xt equivalent:"), stateWidget);
0511     textEquivalentLabel->setBuddy(m_textEquivalent);
0512     QFont font = m_textEquivalent->font();
0513     font.setFamily("monospace");
0514     m_textEquivalent->setFont(font);
0515 
0516     HelpLabel *textEquivalentHelp = new HelpLabel(i18n("What is this for?"),
0517                                                   "<p>" + i18n("When you copy and paste or drag and drop notes to a text editor, this text will be inserted as a textual equivalent of the tag.") + "</p>" +
0518                                                       //      "<p>" + i18n("If filled, this property lets you paste this tag or this state as textual equivalent.") + "<br>" +
0519                                                       i18n("For instance, a list of notes with the <b>To Do</b> and <b>Done</b> tags are exported as lines preceded by <b>[ ]</b> or <b>[x]</b>, "
0520                                                            "representing an empty checkbox and a checked box.") +
0521                                                       "</p>" + "<p align='center'><img src=\":images/tag_export_help.png\"></p>",
0522                                                   stateWidget);
0523     QHBoxLayout *textEquivalentHelpLayout = new QHBoxLayout;
0524     textEquivalentHelpLayout->addWidget(textEquivalentHelp);
0525     textEquivalentHelpLayout->addStretch(255);
0526 
0527     m_onEveryLines = new QCheckBox(i18n("On ever&y line"), stateWidget);
0528 
0529     HelpLabel *onEveryLinesHelp = new HelpLabel(i18n("What does this mean?"),
0530                                                 "<p>" + i18n("When a note has several lines, you can choose to export the tag or the state on the first line or on every line of the note.") + "</p>" +
0531                                                     "<p align='center'><img src=\":images/tag_export_on_every_lines_help.png\"></p>" + "<p>" +
0532                                                     i18n("In the example above, the tag of the top note is only exported on the first line, while the tag of the bottom note is exported on every line of the note."),
0533                                                 stateWidget);
0534     QHBoxLayout *onEveryLinesHelpLayout = new QHBoxLayout;
0535     onEveryLinesHelpLayout->addWidget(onEveryLinesHelp);
0536     onEveryLinesHelpLayout->addStretch(255);
0537 
0538     QGridLayout *textEquivalentGrid = new QGridLayout;
0539     textEquivalentGrid->addWidget(textEquivalentLabel, 0, 0);
0540     textEquivalentGrid->addWidget(m_textEquivalent, 0, 1);
0541     textEquivalentGrid->addLayout(textEquivalentHelpLayout, 0, 2);
0542     textEquivalentGrid->addWidget(m_onEveryLines, 1, 1);
0543     textEquivalentGrid->addLayout(onEveryLinesHelpLayout, 1, 2);
0544     textEquivalentGrid->setColumnStretch(/*col=*/3, /*stretch=*/255);
0545 
0546     KSeparator *separator = new KSeparator(Qt::Horizontal, stateWidget);
0547 
0548     QGridLayout *stateGrid = new QGridLayout(stateWidget);
0549     stateGrid->addWidget(m_stateNameLabel, 0, 0);
0550     stateGrid->addWidget(m_stateName, 0, 1, 1, 6);
0551     stateGrid->addWidget(emblemLabel, 1, 0);
0552     stateGrid->addWidget(emblemWidget, 1, 1, 1, 6);
0553     stateGrid->addWidget(backgroundColorLabel, 1, 5);
0554     stateGrid->addLayout(backgroundColorLayout, 1, 6, 1, 1);
0555     stateGrid->addWidget(textLabel, 2, 0);
0556     stateGrid->addLayout(textLayout, 2, 1, 1, 4);
0557     stateGrid->addWidget(textColorLabel, 2, 5);
0558     stateGrid->addWidget(m_textColor, 2, 6);
0559     stateGrid->addWidget(fontLabel, 3, 0);
0560     stateGrid->addWidget(m_font, 3, 1, 1, 4);
0561     stateGrid->addWidget(fontSizeLabel, 3, 5);
0562     stateGrid->addWidget(m_fontSize, 3, 6);
0563     stateGrid->addWidget(separator, 4, 0, 1, 7);
0564     stateGrid->addLayout(textEquivalentGrid, 5, 0, 1, 7);
0565 
0566     QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget);
0567     rightLayout->addWidget(m_tagBox);
0568     rightLayout->addWidget(m_stateBox);
0569     rightLayout->addStretch();
0570 
0571     layout->addWidget(rightWidget);
0572     rightWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
0573 
0574     // Equalize the width of the first column of the two grids:
0575     int maxWidth = tagNameLabel->sizeHint().width();
0576     maxWidth = qMax(maxWidth, shortcutLabel->sizeHint().width());
0577     maxWidth = qMax(maxWidth, m_stateNameLabel->sizeHint().width());
0578     maxWidth = qMax(maxWidth, emblemLabel->sizeHint().width());
0579     maxWidth = qMax(maxWidth, textLabel->sizeHint().width());
0580     maxWidth = qMax(maxWidth, fontLabel->sizeHint().width());
0581     maxWidth = qMax(maxWidth, backgroundColorLabel->sizeHint().width());
0582     maxWidth = qMax(maxWidth, textEquivalentLabel->sizeHint().width());
0583 
0584     tagNameLabel->setFixedWidth(maxWidth);
0585     m_stateNameLabel->setFixedWidth(maxWidth);
0586     textEquivalentLabel->setFixedWidth(maxWidth);
0587 
0588     // Load Tags:
0589     for (Tag::List::iterator tagIt = Tag::all.begin(); tagIt != Tag::all.end(); ++tagIt)
0590         m_tagCopies.append(new TagCopy(*tagIt));
0591 
0592     TagListViewItem *lastInsertedItem = nullptr;
0593     TagListViewItem *lastInsertedSubItem;
0594     TagListViewItem *item;
0595     TagListViewItem *subItem;
0596     for (TagCopy::List::iterator tagCopyIt = m_tagCopies.begin(); tagCopyIt != m_tagCopies.end(); ++tagCopyIt) {
0597         // New List View Item:
0598         if (lastInsertedItem)
0599             item = new TagListViewItem(m_tags, lastInsertedItem, *tagCopyIt);
0600         else
0601             item = new TagListViewItem(m_tags, *tagCopyIt);
0602         item->setExpanded(true);
0603         lastInsertedItem = item;
0604         // Load
0605         if ((*tagCopyIt)->isMultiState()) {
0606             lastInsertedSubItem = nullptr;
0607             StateCopy::List stateCopies = item->tagCopy()->stateCopies;
0608             for (StateCopy::List::iterator stateCopyIt = stateCopies.begin(); stateCopyIt != stateCopies.end(); ++stateCopyIt) {
0609                 if (lastInsertedSubItem)
0610                     subItem = new TagListViewItem(item, lastInsertedSubItem, *stateCopyIt);
0611                 else
0612                     subItem = new TagListViewItem(item, *stateCopyIt);
0613                 lastInsertedSubItem = subItem;
0614             }
0615         }
0616     }
0617 
0618     // Connect Signals:
0619     connect(m_tagName, &QLineEdit::textChanged, this, &TagsEditDialog::modified);
0620     connect(m_shortcut, &KShortcutWidget::shortcutChanged, this, &TagsEditDialog::modified);
0621     connect(m_inherit, &QCheckBox::stateChanged, this, &TagsEditDialog::modified);
0622     connect(m_allowCrossRefernce, &QCheckBox::clicked, this, &TagsEditDialog::modified);
0623     connect(m_stateName, &QLineEdit::textChanged, this, &TagsEditDialog::modified);
0624     connect(m_emblem, &KIconButton::iconChanged, this, &TagsEditDialog::modified);
0625     connect(m_backgroundColor, &KColorCombo2::colorChanged, this, &TagsEditDialog::modified);
0626     connect(m_bold, &QPushButton::toggled, this, &TagsEditDialog::modified);
0627     connect(m_underline, &QPushButton::toggled, this, &TagsEditDialog::modified);
0628     connect(m_italic, &QPushButton::toggled, this, &TagsEditDialog::modified);
0629     connect(m_strike, &QPushButton::toggled, this, &TagsEditDialog::modified);
0630     connect(m_textColor, &KColorCombo2::colorChanged, this, &TagsEditDialog::modified);
0631     connect(m_font, &QFontComboBox::editTextChanged, this, &TagsEditDialog::modified);
0632     connect(m_fontSize, &FontSizeCombo::editTextChanged, this, &TagsEditDialog::modified);
0633     connect(m_textEquivalent, &QLineEdit::textChanged, this, &TagsEditDialog::modified);
0634     connect(m_onEveryLines, &QCheckBox::stateChanged, this, &TagsEditDialog::modified);
0635 
0636     connect(m_tags, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
0637     connect(m_tags, SIGNAL(deletePressed()), this, SLOT(deleteTag()));
0638     connect(m_tags, SIGNAL(doubleClickedItem()), this, SLOT(renameIt()));
0639 
0640     QTreeWidgetItem *firstItem = m_tags->firstChild();
0641     if (stateToEdit != nullptr) {
0642         TagListViewItem *item = itemForState(stateToEdit);
0643         if (item)
0644             firstItem = item;
0645     }
0646     // Select the first tag unless the first tag is a multi-state tag.
0647     // In this case, select the first state, as it let customize the state AND the associated tag.
0648     if (firstItem) {
0649         if (firstItem->childCount() > 0)
0650             firstItem = firstItem->child(0);
0651         firstItem->setSelected(true);
0652         m_tags->setCurrentItem(firstItem);
0653         currentItemChanged(firstItem);
0654         if (stateToEdit == nullptr)
0655             m_tags->scrollToItem(firstItem);
0656         m_tags->setFocus();
0657     } else {
0658         m_moveUp->setEnabled(false);
0659         m_moveDown->setEnabled(false);
0660         m_deleteTag->setEnabled(false);
0661         m_tagBox->setEnabled(false);
0662         m_stateBox->setEnabled(false);
0663     }
0664     // TODO: Disabled both boxes if no tag!!!
0665 
0666     // Some keyboard shortcuts:       // Ctrl+arrows instead of Alt+arrows (same as Go menu in the main window) because Alt+Down is for combo boxes
0667     QAction *selectAbove = new QAction(this);
0668     selectAbove->setShortcut(Qt::CTRL + Qt::Key_Up);
0669     connect(selectAbove, &QAction::triggered, this, &TagsEditDialog::selectUp);
0670 
0671     QAction *selectBelow = new QAction(this);
0672     selectBelow->setShortcut(Qt::CTRL + Qt::Key_Down);
0673     connect(selectBelow, &QAction::triggered, this, &TagsEditDialog::selectDown);
0674 
0675     QAction *selectLeft = new QAction(this);
0676     selectLeft->setShortcut(Qt::CTRL + Qt::Key_Left);
0677     connect(selectLeft, &QAction::triggered, this, &TagsEditDialog::selectLeft);
0678 
0679     QAction *selectRight = new QAction(this);
0680     selectRight->setShortcut(Qt::CTRL + Qt::Key_Right);
0681     connect(selectRight, &QAction::triggered, this, &TagsEditDialog::selectRight);
0682 
0683     QAction *moveAbove = new QAction(this);
0684     moveAbove->setShortcut(Qt::CTRL + Qt::Key_Up);
0685     connect(moveAbove, &QAction::triggered, this, &TagsEditDialog::moveUp);
0686 
0687     QAction *moveBelow = new QAction(this);
0688     moveBelow->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Down);
0689     connect(moveBelow, &QAction::triggered, this, &TagsEditDialog::moveDown);
0690 
0691     QAction *rename = new QAction(this);
0692     rename->setShortcut(Qt::Key_F2);
0693     connect(rename, &QAction::triggered, this, &TagsEditDialog::renameIt);
0694 
0695     m_tags->setMinimumSize(m_tags->sizeHint().width() * 2, m_tagBox->sizeHint().height() + m_stateBox->sizeHint().height());
0696 
0697     if (addNewTag)
0698         QTimer::singleShot(0, this, SLOT(newTag()));
0699     else
0700         // Once the window initial size is computed and the window show, allow the user to resize it down:
0701         QTimer::singleShot(0, this, SLOT(resetTreeSizeHint()));
0702 }
0703 
0704 TagsEditDialog::~TagsEditDialog()
0705 {
0706 }
0707 
0708 void TagsEditDialog::resetTreeSizeHint()
0709 {
0710     m_tags->setMinimumSize(m_tags->sizeHint());
0711 }
0712 
0713 TagListViewItem *TagsEditDialog::itemForState(State *state)
0714 {
0715     // Browse all tags:
0716     QTreeWidgetItemIterator it(m_tags);
0717     while (*it) {
0718         QTreeWidgetItem *item = *it;
0719 
0720         // Return if we found the tag item:
0721         TagListViewItem *tagItem = (TagListViewItem *)item;
0722         if (tagItem->tagCopy() && tagItem->tagCopy()->oldTag && tagItem->tagCopy()->stateCopies[0]->oldState == state)
0723             return tagItem;
0724 
0725         // Browser all sub-states:
0726         QTreeWidgetItemIterator it2(item);
0727         while (*it2) {
0728             QTreeWidgetItem *subItem = *it2;
0729 
0730             // Return if we found the state item:
0731             TagListViewItem *stateItem = (TagListViewItem *)subItem;
0732             if (stateItem->stateCopy() && stateItem->stateCopy()->oldState && stateItem->stateCopy()->oldState == state)
0733                 return stateItem;
0734 
0735             ++it2;
0736         }
0737 
0738         ++it;
0739     }
0740     return nullptr;
0741 }
0742 
0743 void TagsEditDialog::newTag()
0744 {
0745     // Add to the "model":
0746     TagCopy *newTagCopy = new TagCopy();
0747     newTagCopy->stateCopies[0]->newState->setId("tag_state_" + QString::number(Tag::getNextStateUid())); // TODO: Check if it's really unique
0748     m_tagCopies.append(newTagCopy);
0749     m_addedStates.append(newTagCopy->stateCopies[0]->newState);
0750 
0751     // Add to the "view":
0752     TagListViewItem *item;
0753     if (m_tags->firstChild()) {
0754         // QListView::lastItem is the last item in the tree. If we the last item is a state item, the new tag gets appended to the begin of the list.
0755         TagListViewItem *last = m_tags->lastItem();
0756         if (last->parent())
0757             last = last->parent();
0758         item = new TagListViewItem(m_tags, last, newTagCopy);
0759     } else
0760         item = new TagListViewItem(m_tags, newTagCopy);
0761 
0762     m_deleteTag->setEnabled(true);
0763     m_tagBox->setEnabled(true);
0764 
0765     // Add to the "controller":
0766     m_tags->setCurrentItem(item);
0767     currentItemChanged(item);
0768     item->setSelected(true);
0769     m_tagName->setFocus();
0770 }
0771 
0772 void TagsEditDialog::newState()
0773 {
0774     TagListViewItem *tagItem = m_tags->currentItem();
0775     if (tagItem->parent())
0776         tagItem = ((TagListViewItem *)(tagItem->parent()));
0777     tagItem->setExpanded(true); // Show sub-states if we're adding them for the first time!
0778 
0779     State *firstState = tagItem->tagCopy()->stateCopies[0]->newState;
0780 
0781     // Add the first state to the "view". From now on, it's a multi-state tag:
0782     if (tagItem->childCount() <= 0) {
0783         firstState->setName(tagItem->tagCopy()->newTag->name());
0784         // Force emblem to exists for multi-state tags:
0785         if (firstState->emblem().isEmpty())
0786             firstState->setEmblem("empty");
0787         new TagListViewItem(tagItem, tagItem->tagCopy()->stateCopies[0]);
0788     }
0789 
0790     // Add to the "model":
0791     StateCopy *newStateCopy = new StateCopy();
0792     firstState->copyTo(newStateCopy->newState);
0793     newStateCopy->newState->setId("tag_state_" + QString::number(Tag::getNextStateUid())); // TODO: Check if it's really unique
0794     newStateCopy->newState->setName(QString());                                            // We copied it too but it's likely the name will not be the same
0795     tagItem->tagCopy()->stateCopies.append(newStateCopy);
0796     m_addedStates.append(newStateCopy->newState);
0797 
0798     // Add to the "view":
0799     TagListViewItem *item = new TagListViewItem(tagItem, tagItem->lastChild(), newStateCopy);
0800 
0801     // Add to the "controller":
0802     m_tags->setCurrentItem(item);
0803     currentItemChanged(item);
0804     m_stateName->setFocus();
0805 }
0806 
0807 void TagsEditDialog::moveUp()
0808 {
0809     if (!m_moveUp->isEnabled()) // Trggered by keyboard shortcut
0810         return;
0811 
0812     TagListViewItem *tagItem = m_tags->currentItem();
0813 
0814     // Move in the list view:
0815     int idx = 0;
0816     QList<QTreeWidgetItem *> children;
0817     if (tagItem->parent()) {
0818         TagListViewItem *parentItem = tagItem->parent();
0819         idx = parentItem->indexOfChild(tagItem);
0820         if (idx > 0) {
0821             tagItem = (TagListViewItem *)parentItem->takeChild(idx);
0822             children = tagItem->takeChildren();
0823             parentItem->insertChild(idx - 1, tagItem);
0824             tagItem->insertChildren(0, children);
0825             tagItem->setExpanded(true);
0826         }
0827     } else {
0828         idx = m_tags->indexOfTopLevelItem(tagItem);
0829         if (idx > 0) {
0830             tagItem = (TagListViewItem *)m_tags->takeTopLevelItem(idx);
0831             children = tagItem->takeChildren();
0832             m_tags->insertTopLevelItem(idx - 1, tagItem);
0833             tagItem->insertChildren(0, children);
0834             tagItem->setExpanded(true);
0835         }
0836     }
0837 
0838     m_tags->setCurrentItem(tagItem);
0839 
0840     // Move in the value list:
0841     if (tagItem->tagCopy()) {
0842         int pos = m_tagCopies.indexOf(tagItem->tagCopy());
0843         m_tagCopies.removeAll(tagItem->tagCopy());
0844         int i = 0;
0845         for (TagCopy::List::iterator it = m_tagCopies.begin(); it != m_tagCopies.end(); ++it, ++i)
0846             if (i == pos - 1) {
0847                 m_tagCopies.insert(it, tagItem->tagCopy());
0848                 break;
0849             }
0850     } else {
0851         StateCopy::List &stateCopies = ((TagListViewItem *)(tagItem->parent()))->tagCopy()->stateCopies;
0852         int pos = stateCopies.indexOf(tagItem->stateCopy());
0853         stateCopies.removeAll(tagItem->stateCopy());
0854         int i = 0;
0855         for (StateCopy::List::iterator it = stateCopies.begin(); it != stateCopies.end(); ++it, ++i)
0856             if (i == pos - 1) {
0857                 stateCopies.insert(it, tagItem->stateCopy());
0858                 break;
0859             }
0860     }
0861 
0862     ensureCurrentItemVisible();
0863 
0864     m_moveDown->setEnabled(tagItem->nextSibling() != nullptr);
0865     m_moveUp->setEnabled(tagItem->prevSibling() != nullptr);
0866 }
0867 
0868 void TagsEditDialog::moveDown()
0869 {
0870     if (!m_moveDown->isEnabled()) // Trggered by keyboard shortcut
0871         return;
0872 
0873     TagListViewItem *tagItem = m_tags->currentItem();
0874 
0875     // Move in the list view:
0876     int idx = 0;
0877     QList<QTreeWidgetItem *> children;
0878     if (tagItem->parent()) {
0879         TagListViewItem *parentItem = tagItem->parent();
0880         idx = parentItem->indexOfChild(tagItem);
0881         if (idx < parentItem->childCount() - 1) {
0882             children = tagItem->takeChildren();
0883             tagItem = (TagListViewItem *)parentItem->takeChild(idx);
0884             parentItem->insertChild(idx + 1, tagItem);
0885             tagItem->insertChildren(0, children);
0886             tagItem->setExpanded(true);
0887         }
0888     } else {
0889         idx = m_tags->indexOfTopLevelItem(tagItem);
0890         if (idx < m_tags->topLevelItemCount() - 1) {
0891             children = tagItem->takeChildren();
0892             tagItem = (TagListViewItem *)m_tags->takeTopLevelItem(idx);
0893             m_tags->insertTopLevelItem(idx + 1, tagItem);
0894             tagItem->insertChildren(0, children);
0895             tagItem->setExpanded(true);
0896         }
0897     }
0898 
0899     m_tags->setCurrentItem(tagItem);
0900 
0901     // Move in the value list:
0902     if (tagItem->tagCopy()) {
0903         uint pos = m_tagCopies.indexOf(tagItem->tagCopy());
0904         m_tagCopies.removeAll(tagItem->tagCopy());
0905         if (pos == (uint)m_tagCopies.count() - 1) // Insert at end: iterator does not go there
0906             m_tagCopies.append(tagItem->tagCopy());
0907         else {
0908             uint i = 0;
0909             for (TagCopy::List::iterator it = m_tagCopies.begin(); it != m_tagCopies.end(); ++it, ++i)
0910                 if (i == pos + 1) {
0911                     m_tagCopies.insert(it, tagItem->tagCopy());
0912                     break;
0913                 }
0914         }
0915     } else {
0916         StateCopy::List &stateCopies = ((TagListViewItem *)(tagItem->parent()))->tagCopy()->stateCopies;
0917         uint pos = stateCopies.indexOf(tagItem->stateCopy());
0918         stateCopies.removeAll(tagItem->stateCopy());
0919         if (pos == (uint)stateCopies.count() - 1) // Insert at end: iterator does not go there
0920             stateCopies.append(tagItem->stateCopy());
0921         else {
0922             uint i = 0;
0923             for (StateCopy::List::iterator it = stateCopies.begin(); it != stateCopies.end(); ++it, ++i)
0924                 if (i == pos + 1) {
0925                     stateCopies.insert(it, tagItem->stateCopy());
0926                     break;
0927                 }
0928         }
0929     }
0930 
0931     ensureCurrentItemVisible();
0932 
0933     m_moveDown->setEnabled(tagItem->nextSibling() != nullptr);
0934     m_moveUp->setEnabled(tagItem->prevSibling() != nullptr);
0935 }
0936 
0937 void TagsEditDialog::selectUp()
0938 {
0939     QKeyEvent *keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::KeyboardModifiers(), nullptr);
0940     QApplication::postEvent(m_tags, keyEvent);
0941 }
0942 
0943 void TagsEditDialog::selectDown()
0944 {
0945     QKeyEvent *keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::KeyboardModifiers(), nullptr);
0946     QApplication::postEvent(m_tags, keyEvent);
0947 }
0948 
0949 void TagsEditDialog::selectLeft()
0950 {
0951     QKeyEvent *keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::KeyboardModifiers(), nullptr);
0952     QApplication::postEvent(m_tags, keyEvent);
0953 }
0954 
0955 void TagsEditDialog::selectRight()
0956 {
0957     QKeyEvent *keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::KeyboardModifiers(), nullptr);
0958     QApplication::postEvent(m_tags, keyEvent);
0959 }
0960 
0961 void TagsEditDialog::deleteTag()
0962 {
0963     if (!m_deleteTag->isEnabled())
0964         return;
0965 
0966     TagListViewItem *item = m_tags->currentItem();
0967 
0968     int result = KMessageBox::Continue;
0969     if (item->tagCopy() && item->tagCopy()->oldTag)
0970         result = KMessageBox::warningContinueCancel(this, i18n("Deleting the tag will remove it from every note it is currently assigned to."), i18n("Confirm Delete Tag"), KGuiItem(i18n("Delete Tag"), "edit-delete"));
0971     else if (item->stateCopy() && item->stateCopy()->oldState)
0972         result = KMessageBox::warningContinueCancel(this, i18n("Deleting the state will remove the tag from every note the state is currently assigned to."), i18n("Confirm Delete State"), KGuiItem(i18n("Delete State"), "edit-delete"));
0973     if (result != KMessageBox::Continue)
0974         return;
0975 
0976     if (item->tagCopy()) {
0977         StateCopy::List stateCopies = item->tagCopy()->stateCopies;
0978         for (StateCopy::List::iterator stateCopyIt = stateCopies.begin(); stateCopyIt != stateCopies.end(); ++stateCopyIt) {
0979             StateCopy *stateCopy = *stateCopyIt;
0980             if (stateCopy->oldState) {
0981                 m_deletedStates.append(stateCopy->oldState);
0982                 m_addedStates.removeAll(stateCopy->oldState);
0983             }
0984             m_addedStates.removeAll(stateCopy->newState);
0985         }
0986         m_tagCopies.removeAll(item->tagCopy());
0987         // Remove the new tag, to avoid keyboard-shortcut clashes:
0988         delete item->tagCopy()->newTag;
0989     } else {
0990         TagListViewItem *parentItem = item->parent();
0991         // Remove the state:
0992         parentItem->tagCopy()->stateCopies.removeAll(item->stateCopy());
0993         if (item->stateCopy()->oldState) {
0994             m_deletedStates.append(item->stateCopy()->oldState);
0995             m_addedStates.removeAll(item->stateCopy()->oldState);
0996         }
0997         m_addedStates.removeAll(item->stateCopy()->newState);
0998         delete item;
0999         item = nullptr;
1000         // Transform to single-state tag if needed:
1001         if (parentItem->childCount() == 1) {
1002             delete parentItem->child(0);
1003             m_tags->setCurrentItem(parentItem);
1004         }
1005     }
1006 
1007     delete item;
1008     if (m_tags->currentItem())
1009         m_tags->currentItem()->setSelected(true);
1010 
1011     if (!m_tags->firstChild()) {
1012         m_deleteTag->setEnabled(false);
1013         m_tagBox->setEnabled(false);
1014         m_stateBox->setEnabled(false);
1015     }
1016 }
1017 
1018 void TagsEditDialog::renameIt()
1019 {
1020     if (m_tags->currentItem()->tagCopy())
1021         m_tagName->setFocus();
1022     else
1023         m_stateName->setFocus();
1024 }
1025 
1026 void TagsEditDialog::capturedShortcut(const QKeySequence &shortcut)
1027 {
1028     Q_UNUSED(shortcut);
1029     // TODO: Validate it!
1030     // m_shortcut->setShortcut(shortcut);
1031 }
1032 
1033 void TagsEditDialog::removeShortcut()
1034 {
1035     // m_shortcut->setShortcut(QKeySequence());
1036     modified();
1037 }
1038 
1039 void TagsEditDialog::removeEmblem()
1040 {
1041     m_emblem->resetIcon();
1042     modified();
1043 }
1044 
1045 void TagsEditDialog::modified()
1046 {
1047     if (m_loading)
1048         return;
1049 
1050     TagListViewItem *tagItem = m_tags->currentItem();
1051     if (tagItem == nullptr)
1052         return;
1053 
1054     if (tagItem->tagCopy()) {
1055         if (tagItem->tagCopy()->isMultiState()) {
1056             saveTagTo(tagItem->tagCopy()->newTag);
1057         } else {
1058             saveTagTo(tagItem->tagCopy()->newTag);
1059             saveStateTo(tagItem->tagCopy()->stateCopies[0]->newState);
1060         }
1061     } else if (tagItem->stateCopy()) {
1062         saveTagTo(((TagListViewItem *)(tagItem->parent()))->tagCopy()->newTag);
1063         saveStateTo(tagItem->stateCopy()->newState);
1064     }
1065 
1066     m_tags->currentItem()->setup();
1067     if (m_tags->currentItem()->parent())
1068         m_tags->currentItem()->parent()->setup();
1069 
1070     m_removeShortcut->setEnabled(!m_shortcut->shortcut().isEmpty());
1071     m_removeEmblem->setEnabled(!m_emblem->icon().isEmpty() && !m_tags->currentItem()->isEmblemObligatory());
1072     m_onEveryLines->setEnabled(!m_textEquivalent->text().isEmpty());
1073 }
1074 
1075 void TagsEditDialog::currentItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *nextItem)
1076 {
1077     Q_UNUSED(nextItem);
1078     if (item == nullptr)
1079         return;
1080 
1081     m_loading = true;
1082 
1083     TagListViewItem *tagItem = (TagListViewItem *)item;
1084     if (tagItem->tagCopy()) {
1085         if (tagItem->tagCopy()->isMultiState()) {
1086             loadTagFrom(tagItem->tagCopy()->newTag);
1087             loadBlankState();
1088             m_stateBox->setEnabled(false);
1089             m_stateBox->setTitle(i18n("State"));
1090             m_stateNameLabel->setEnabled(true);
1091             m_stateName->setEnabled(true);
1092         } else {
1093             loadTagFrom(tagItem->tagCopy()->newTag); // TODO: No duplicate
1094             loadStateFrom(tagItem->tagCopy()->stateCopies[0]->newState);
1095             m_stateBox->setEnabled(true);
1096             m_stateBox->setTitle(i18n("Appearance"));
1097             m_stateName->setText(QString());
1098             m_stateNameLabel->setEnabled(false);
1099             m_stateName->setEnabled(false);
1100         }
1101     } else if (tagItem->stateCopy()) {
1102         loadTagFrom(((TagListViewItem *)(tagItem->parent()))->tagCopy()->newTag);
1103         loadStateFrom(tagItem->stateCopy()->newState);
1104         m_stateBox->setEnabled(true);
1105         m_stateBox->setTitle(i18n("State"));
1106         m_stateNameLabel->setEnabled(true);
1107         m_stateName->setEnabled(true);
1108     }
1109 
1110     ensureCurrentItemVisible();
1111 
1112     m_loading = false;
1113 }
1114 
1115 void TagsEditDialog::ensureCurrentItemVisible()
1116 {
1117     TagListViewItem *tagItem = m_tags->currentItem();
1118 
1119     // Ensure the tag and the states (if available) to be visible, but if there is a looooot of states,
1120     // ensure the tag is still visible, even if the last states are not...
1121     m_tags->scrollToItem(tagItem);
1122 
1123     int idx = 0;
1124 
1125     if (tagItem->parent()) {
1126         idx = ((QTreeWidgetItem *)tagItem->parent())->indexOfChild(tagItem);
1127         m_moveDown->setEnabled(idx < ((QTreeWidgetItem *)tagItem->parent())->childCount());
1128     } else {
1129         idx = m_tags->indexOfTopLevelItem(tagItem);
1130         m_moveDown->setEnabled(idx < m_tags->topLevelItemCount());
1131     }
1132 
1133     m_moveUp->setEnabled(idx > 0);
1134 }
1135 
1136 void TagsEditDialog::loadBlankState()
1137 {
1138     QFont defaultFont;
1139     m_stateName->setText(QString());
1140     m_emblem->resetIcon();
1141     m_removeEmblem->setEnabled(false);
1142     m_backgroundColor->setColor(QColor());
1143     m_bold->setChecked(false);
1144     m_underline->setChecked(false);
1145     m_italic->setChecked(false);
1146     m_strike->setChecked(false);
1147     m_textColor->setColor(QColor());
1148     // m_font->setCurrentIndex(0);
1149     m_font->setCurrentFont(defaultFont.family());
1150     m_fontSize->setCurrentIndex(0);
1151     m_textEquivalent->setText(QString());
1152     m_onEveryLines->setChecked(false);
1153     m_allowCrossRefernce->setChecked(false);
1154 }
1155 
1156 void TagsEditDialog::loadStateFrom(State *state)
1157 {
1158     m_stateName->setText(state->name());
1159     if (state->emblem().isEmpty())
1160         m_emblem->resetIcon();
1161     else
1162         m_emblem->setIcon(state->emblem());
1163     m_removeEmblem->setEnabled(!state->emblem().isEmpty() && !m_tags->currentItem()->isEmblemObligatory());
1164     m_backgroundColor->setColor(state->backgroundColor());
1165     m_bold->setChecked(state->bold());
1166     m_underline->setChecked(state->underline());
1167     m_italic->setChecked(state->italic());
1168     m_strike->setChecked(state->strikeOut());
1169     m_textColor->setColor(state->textColor());
1170     m_textEquivalent->setText(state->textEquivalent());
1171     m_onEveryLines->setChecked(state->onAllTextLines());
1172     m_allowCrossRefernce->setChecked(state->allowCrossReferences());
1173 
1174     QFont defaultFont;
1175     if (state->fontName().isEmpty())
1176         m_font->setCurrentFont(defaultFont.family());
1177     else
1178         m_font->setCurrentFont(state->fontName());
1179 
1180     if (state->fontSize() == -1)
1181         m_fontSize->setCurrentIndex(0);
1182     else
1183         m_fontSize->setItemText(m_fontSize->currentIndex(), QString::number(state->fontSize()));
1184 }
1185 
1186 void TagsEditDialog::loadTagFrom(Tag *tag)
1187 {
1188     m_tagName->setText(tag->name());
1189     QList<QKeySequence> shortcuts {tag->shortcut()};
1190     m_shortcut->setShortcut(shortcuts);
1191     m_removeShortcut->setEnabled(!tag->shortcut().isEmpty());
1192     m_inherit->setChecked(tag->inheritedBySiblings());
1193 }
1194 
1195 void TagsEditDialog::saveStateTo(State *state)
1196 {
1197     state->setName(m_stateName->text());
1198     state->setEmblem(m_emblem->icon());
1199     state->setBackgroundColor(m_backgroundColor->color());
1200     state->setBold(m_bold->isChecked());
1201     state->setUnderline(m_underline->isChecked());
1202     state->setItalic(m_italic->isChecked());
1203     state->setStrikeOut(m_strike->isChecked());
1204     state->setTextColor(m_textColor->color());
1205     state->setTextEquivalent(m_textEquivalent->text());
1206     state->setOnAllTextLines(m_onEveryLines->isChecked());
1207     state->setAllowCrossReferences(m_allowCrossRefernce->isChecked());
1208 
1209     if (m_font->currentIndex() == 0)
1210         state->setFontName(QString());
1211     else
1212         state->setFontName(m_font->currentFont().family());
1213 
1214     bool conversionOk;
1215     int fontSize = m_fontSize->currentText().toInt(&conversionOk);
1216     if (conversionOk)
1217         state->setFontSize(fontSize);
1218     else
1219         state->setFontSize(-1);
1220 }
1221 
1222 void TagsEditDialog::saveTagTo(Tag *tag)
1223 {
1224     tag->setName(m_tagName->text());
1225 
1226     QKeySequence shortcut;
1227     if (m_shortcut->shortcut().count() > 0)
1228         shortcut = m_shortcut->shortcut()[0];
1229     tag->setShortcut(shortcut);
1230 
1231     tag->setInheritedBySiblings(m_inherit->isChecked());
1232 }
1233 
1234 void TagsEditDialog::reject()
1235 {
1236     // All copies of tag have a shortcut, that is stored as a QAction.
1237     // So, shortcuts are duplicated, and if the user press one tag keyboard-shortcut in the main window, there is a conflict.
1238     // We then should delete every copies:
1239     for (TagCopy::List::iterator tagCopyIt = m_tagCopies.begin(); tagCopyIt != m_tagCopies.end(); ++tagCopyIt) {
1240         delete (*tagCopyIt)->newTag;
1241     }
1242 
1243     QDialog::reject();
1244 }
1245 
1246 void TagsEditDialog::accept()
1247 {
1248     Tag::all.clear();
1249     for (TagCopy::List::iterator tagCopyIt = m_tagCopies.begin(); tagCopyIt != m_tagCopies.end(); ++tagCopyIt) {
1250         TagCopy *tagCopy = *tagCopyIt;
1251         // Copy changes to the tag and append in the list of tags::
1252         if (tagCopy->oldTag) {
1253             tagCopy->newTag->copyTo(tagCopy->oldTag);
1254             delete tagCopy->newTag;
1255         }
1256         Tag *tag = (tagCopy->oldTag ? tagCopy->oldTag : tagCopy->newTag);
1257         Tag::all.append(tag);
1258         // And change all states:
1259         State::List &states = tag->states();
1260         StateCopy::List &stateCopies = tagCopy->stateCopies;
1261         states.clear();
1262         for (StateCopy::List::iterator stateCopyIt = stateCopies.begin(); stateCopyIt != stateCopies.end(); ++stateCopyIt) {
1263             StateCopy *stateCopy = *stateCopyIt;
1264             // Copy changes to the state and append in the list of tags:
1265             if (stateCopy->oldState)
1266                 stateCopy->newState->copyTo(stateCopy->oldState);
1267             State *state = (stateCopy->oldState ? stateCopy->oldState : stateCopy->newState);
1268             states.append(state);
1269             state->setParentTag(tag);
1270         }
1271     }
1272     Tag::saveTags();
1273     Tag::updateCaches();
1274 
1275     // Notify removed states and tags, and then remove them:
1276     if (!m_deletedStates.isEmpty())
1277         Global::bnpView->removedStates(m_deletedStates);
1278 
1279     // Update every note (change colors, size because of font change or added/removed emblems...):
1280     Global::bnpView->relayoutAllBaskets();
1281     Global::bnpView->recomputeAllStyles();
1282 
1283     QDialog::accept();
1284 }
1285 
1286 void TagListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
1287 {
1288     //    TagListViewItem* thisItem  = qvariant_cast<TagListViewItem*>(index.data());
1289     //    qDebug() << "Pointer is: " << thisItem << endl;
1290     QItemDelegate::paint(painter, option, index);
1291 }
1292 
1293 #include "moc_tagsedit.cpp"