File indexing completed on 2024-04-28 03:40:31
0001 /*************************************************************************** 0002 * Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de * 0003 * (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 0021 #include "phrasebookdialog.h" 0022 0023 // include files for Qt 0024 #include <QClipboard> 0025 #include <QFileDialog> 0026 #include <QMimeData> 0027 #include <QStack> 0028 #include <QStandardPaths> 0029 0030 // include files for KDE 0031 #include <KActionMenu> 0032 #include <KMessageBox> 0033 #include <KToolBarPopupAction> 0034 #include <KXMLGUIFactory> 0035 0036 #include "phrasebook.h" 0037 0038 #include <QDebug> 0039 #include <kwidgetsaddons_version.h> 0040 0041 const int kTextColumn = 0; 0042 const int kShortcutColumn = 1; 0043 0044 const QString kName = QStringLiteral("name"); 0045 const QString kShortcut = QStringLiteral("shortcut"); 0046 const QString kPhraseBook = QStringLiteral("phrasebook"); 0047 const QString kPhrase = QStringLiteral("phrase"); 0048 0049 const QString kPhraseBookXML = QStringLiteral("<phrasebook name=\"%1\">\n%2</phrasebook>\n"); 0050 const QString kPhraseXML = QStringLiteral("<phrase shortcut=\"%2\">%1</phrase>\n"); 0051 const QString kWholeBookXML = QStringLiteral( 0052 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 0053 "<!DOCTYPE phrasebook>\n" 0054 "<phrasebook>\n%1" 0055 "</phrasebook>"); 0056 0057 const QIcon kPhraseBookIcon = QIcon::fromTheme(kPhraseBook); 0058 const QIcon kPhraseIcon = QIcon::fromTheme(kPhrase); 0059 0060 StandardPhraseBookInsertAction::StandardPhraseBookInsertAction(const QUrl &url, 0061 const QString &name, 0062 const QObject *receiver, 0063 const char *slot, 0064 KActionCollection *parent) 0065 : QAction(QIcon::fromTheme(QStringLiteral("phrasebook")), name, parent) 0066 { 0067 this->url = url; 0068 connect(this, SIGNAL(triggered(bool)), this, SLOT(slotActivated())); 0069 connect(this, SIGNAL(slotActivated(QUrl)), receiver, slot); 0070 parent->addAction(name, this); 0071 } 0072 0073 StandardPhraseBookInsertAction::~StandardPhraseBookInsertAction() 0074 { 0075 } 0076 0077 void StandardPhraseBookInsertAction::slotActivated() 0078 { 0079 Q_EMIT slotActivated(url); 0080 } 0081 0082 namespace PhraseBookPrivate 0083 { 0084 PhraseBookDialog *instance = nullptr; 0085 } 0086 0087 PhraseBookDialog::PhraseBookDialog() 0088 : KXmlGuiWindow(nullptr) 0089 { 0090 // Create model with 2 columns and no rows 0091 m_bookModel = new QStandardItemModel(0, 2, this); 0092 m_rootItem = m_bookModel->invisibleRootItem(); 0093 m_bookModel->setHeaderData(kTextColumn, Qt::Horizontal, i18n("Phrase")); 0094 m_bookModel->setHeaderData(kShortcutColumn, Qt::Horizontal, i18n("Shortcut")); 0095 0096 setObjectName(QStringLiteral("phraseEditDialog")); 0097 setWindowTitle(i18n("Phrase Book")); 0098 initGUI(); 0099 initActions(); 0100 initStandardPhraseBooks(); 0101 QString standardBook = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("standard.phrasebook")); 0102 if (!standardBook.isNull() && !standardBook.isEmpty()) { 0103 QFile file(standardBook); 0104 file.open(QIODevice::ReadOnly); 0105 QDomDocument document; 0106 document.setContent(&file); 0107 0108 const QDomNodeList nodes = document.documentElement().childNodes(); 0109 for (int i = 0; i < nodes.count(); ++i) { 0110 deserializeBook(nodes.at(i), m_rootItem); 0111 } 0112 0113 selectionChanged(); 0114 phrasebookChanged = false; 0115 fileSave->setEnabled(false); 0116 } 0117 0118 // Watch any changes in the model. 0119 connect(m_bookModel, &QAbstractItemModel::dataChanged, this, &PhraseBookDialog::slotModelChanged); 0120 connect(m_bookModel, &QAbstractItemModel::rowsInserted, this, &PhraseBookDialog::slotModelChanged); 0121 connect(m_bookModel, &QAbstractItemModel::rowsMoved, this, &PhraseBookDialog::slotModelChanged); 0122 connect(m_bookModel, &QAbstractItemModel::rowsRemoved, this, &PhraseBookDialog::slotModelChanged); 0123 0124 // printer = 0; 0125 // i18n("Edit Phrase Book") 0126 } 0127 0128 PhraseBookDialog *PhraseBookDialog::get() 0129 { 0130 if (PhraseBookPrivate::instance == nullptr) 0131 PhraseBookPrivate::instance = new PhraseBookDialog(); 0132 return PhraseBookPrivate::instance; 0133 } 0134 0135 PhraseBookDialog::~PhraseBookDialog() 0136 { 0137 PhraseBookPrivate::instance = nullptr; 0138 // delete printer; 0139 } 0140 0141 QStandardItem *PhraseBookDialog::deserializeBook(const QDomNode &node, QStandardItem *parent) 0142 { 0143 QString text; 0144 QString shortcut; 0145 bool isBook = (node.nodeName() == kPhraseBook); 0146 text = isBook ? node.attributes().namedItem(kName).nodeValue() : node.lastChild().nodeValue(); 0147 shortcut = isBook ? QString() : node.attributes().namedItem(kShortcut).nodeValue(); 0148 0149 QStandardItem *item = isBook ? new QStandardItem(kPhraseBookIcon, text) : new QStandardItem(kPhraseIcon, text); 0150 QStandardItem *shortcutItem = new QStandardItem(shortcut); 0151 0152 if (!isBook) { 0153 item->setDropEnabled(false); 0154 shortcutItem->setDropEnabled(false); 0155 } 0156 QList<QStandardItem *> items; 0157 items << item << shortcutItem; 0158 if (parent) 0159 parent->appendRow(items); 0160 else 0161 m_bookModel->appendRow(items); 0162 0163 if (isBook) { 0164 // Iterate over the document creating QStandardItems as needed 0165 const QDomNodeList childNodes = node.childNodes(); 0166 for (int i = 0; i < childNodes.count(); ++i) { 0167 const QDomNode child = childNodes.at(i); 0168 deserializeBook(child, item); 0169 } 0170 } 0171 return item; 0172 } 0173 0174 QString PhraseBookDialog::serializeBook(const QModelIndex &index) 0175 { 0176 QString value; 0177 if (index.isValid()) { 0178 QStandardItem *item = m_bookModel->itemFromIndex(index); 0179 QStandardItem *shortcutItem = m_bookModel->itemFromIndex(index.sibling(index.row(), kShortcutColumn)); 0180 bool isBook = item->isDropEnabled(); // We know it's a book if it's drop enabled 0181 if (isBook) { 0182 QString childrenText; 0183 for (int i = 0; i < item->rowCount(); ++i) { 0184 childrenText += serializeBook(index.model()->index(i, 0, index)); 0185 } 0186 value = kPhraseBookXML.arg(item->text(), childrenText); 0187 } else { 0188 value = kPhraseXML.arg(item->text(), shortcutItem->text()); 0189 } 0190 } else { 0191 // Do the whole model, inside a <phrasebook> tag. 0192 int rows = m_bookModel->rowCount(QModelIndex()); 0193 QString childrenText; 0194 for (int i = 0; i < rows; ++i) { 0195 childrenText += serializeBook(m_bookModel->index(i, 0)); 0196 } 0197 value = kWholeBookXML.arg(childrenText); 0198 } 0199 return value; 0200 } 0201 0202 void PhraseBookDialog::initGUI() 0203 { 0204 QWidget *page = new QWidget(this); 0205 0206 m_ui = new Ui::PhraseBookDialog(); 0207 m_ui->setupUi(page); 0208 setCentralWidget(page); 0209 0210 m_ui->treeView->setModel(m_bookModel); 0211 connect(m_ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PhraseBookDialog::selectionChanged); 0212 connect(m_ui->treeView, &QWidget::customContextMenuRequested, this, &PhraseBookDialog::contextMenuRequested); 0213 connectEditor(); 0214 } 0215 0216 void PhraseBookDialog::slotModelChanged() 0217 { 0218 phrasebookChanged = true; 0219 fileSave->setEnabled(true); 0220 } 0221 0222 void PhraseBookDialog::initActions() 0223 { 0224 // The file menu 0225 fileNewPhrase = actionCollection()->addAction(QStringLiteral("file_new_phrase")); 0226 fileNewPhrase->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); 0227 fileNewPhrase->setText(i18n("&New Phrase")); 0228 connect(fileNewPhrase, &QAction::triggered, this, &PhraseBookDialog::slotAddPhrase); 0229 fileNewPhrase->setToolTip(i18n("Adds a new phrase")); 0230 fileNewPhrase->setWhatsThis(i18n("Adds a new phrase")); 0231 0232 fileNewBook = actionCollection()->addAction(QStringLiteral("file_new_book")); 0233 fileNewBook->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); 0234 fileNewBook->setText(i18n("New Phrase &Book")); 0235 connect(fileNewBook, &QAction::triggered, this, &PhraseBookDialog::slotAddPhrasebook); 0236 fileNewBook->setToolTip(i18n("Adds a new phrase book into which other books and phrases can be placed")); 0237 fileNewBook->setWhatsThis(i18n("Adds a new phrase book into which other books and phrases can be placed")); 0238 0239 fileSave = KStandardAction::save(this, &PhraseBookDialog::slotSave, actionCollection()); 0240 fileSave->setToolTip(i18n("Saves the phrase book onto the hard disk")); 0241 fileSave->setWhatsThis(i18n("Saves the phrase book onto the hard disk")); 0242 0243 fileImport = actionCollection()->addAction(QStringLiteral("file_import")); 0244 fileImport->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); 0245 fileImport->setText(i18n("&Import...")); 0246 connect(fileImport, SIGNAL(triggered(bool)), this, SLOT(slotImportPhrasebook())); 0247 fileImport->setToolTip(i18n("Imports a file and adds its contents to the phrase book")); 0248 fileImport->setWhatsThis(i18n("Imports a file and adds its contents to the phrase book")); 0249 0250 toolbarImport = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("document-open")), i18n("&Import..."), this); 0251 actionCollection()->addAction(QStringLiteral("toolbar_import"), toolbarImport); 0252 connect(toolbarImport, SIGNAL(triggered(bool)), this, SLOT(slotImportPhrasebook())); 0253 toolbarImport->setToolTip(i18n("Imports a file and adds its contents to the phrase book")); 0254 toolbarImport->setWhatsThis(i18n("Imports a file and adds its contents to the phrase book")); 0255 0256 fileImportStandardBook = actionCollection()->add<KActionMenu>(QStringLiteral("file_import_standard_book")); 0257 fileImportStandardBook->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); 0258 fileImportStandardBook->setText(i18n("I&mport Standard Phrase Book")); 0259 fileImportStandardBook->setToolTip(i18n("Imports a standard phrase book and adds its contents to the phrase book")); 0260 fileImportStandardBook->setWhatsThis(i18n("Imports a standard phrase book and adds its contents to the phrase book")); 0261 0262 fileExport = actionCollection()->addAction(QStringLiteral("file_export")); 0263 fileExport->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); 0264 fileExport->setText(i18n("&Export...")); 0265 connect(fileExport, &QAction::triggered, this, &PhraseBookDialog::slotExportPhrasebook); 0266 fileExport->setToolTip(i18n("Exports the currently selected phrase(s) or phrase book(s) into a file")); 0267 fileExport->setWhatsThis(i18n("Exports the currently selected phrase(s) or phrase book(s) into a file")); 0268 0269 // filePrint = KStandardAction::print(this, SLOT(slotPrint()), actionCollection()); 0270 // filePrint->setToolTip(i18n("Prints the currently selected phrase(s) or phrase book(s)")); 0271 // filePrint->setWhatsThis (i18n("Prints the currently selected phrase(s) or phrase book(s)")); 0272 0273 fileClose = KStandardAction::close(this, &PhraseBookDialog::close, actionCollection()); 0274 fileClose->setToolTip(i18n("Closes the window")); 0275 fileClose->setWhatsThis(i18n("Closes the window")); 0276 0277 // The edit menu 0278 editCut = KStandardAction::cut(this, &PhraseBookDialog::slotCut, actionCollection()); 0279 editCut->setToolTip(i18n("Cuts the currently selected entries from the phrase book and puts it to the clipboard")); 0280 editCut->setWhatsThis(i18n("Cuts the currently selected entries from the phrase book and puts it to the clipboard")); 0281 0282 editCopy = KStandardAction::copy(this, &PhraseBookDialog::slotCopy, actionCollection()); 0283 editCopy->setToolTip(i18n("Copies the currently selected entry from the phrase book to the clipboard")); 0284 editCopy->setWhatsThis(i18n("Copies the currently selected entry from the phrase book to the clipboard")); 0285 0286 editPaste = KStandardAction::paste(this, &PhraseBookDialog::slotPaste, actionCollection()); 0287 editPaste->setToolTip(i18n("Pastes the clipboard contents to current position")); 0288 editPaste->setWhatsThis(i18n("Pastes the clipboard contents at the current cursor position into the edit field.")); 0289 0290 editDelete = actionCollection()->addAction(QStringLiteral("edit_delete")); 0291 editDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); 0292 editDelete->setText(i18n("&Delete")); 0293 connect(editDelete, &QAction::triggered, this, &PhraseBookDialog::slotRemove); 0294 editDelete->setToolTip(i18n("Deletes the selected entries from the phrase book")); 0295 editDelete->setWhatsThis(i18n("Deletes the selected entries from the phrase book")); 0296 0297 // use the absolute path to your kmouthui.rc file for testing purpose in createGUI(); 0298 createGUI(QStringLiteral("phrasebookdialogui.rc")); 0299 } 0300 0301 void PhraseBookDialog::initStandardPhraseBooks() 0302 { 0303 StandardBookList bookPaths = PhraseBook::standardPhraseBooks(); 0304 0305 KActionMenu *parent = fileImportStandardBook; 0306 QStringList currentNamePath; 0307 currentNamePath << QStringLiteral("x"); 0308 QStack<KActionMenu *> stack; 0309 StandardBookList::iterator it; 0310 for (it = bookPaths.begin(); it != bookPaths.end(); ++it) { 0311 QUrl url = QUrl::fromLocalFile((*it).filename); 0312 0313 QString namePath = QStringLiteral("x") + (*it).path; 0314 QStringList dirs = namePath.split(QLatin1Char('/')); 0315 0316 QStringList::iterator it1 = currentNamePath.begin(); 0317 QStringList::iterator it2 = dirs.begin(); 0318 for (; (it1 != currentNamePath.end()) && (it2 != dirs.end()) && (*it1 == *it2); ++it1, ++it2) 0319 ; 0320 0321 for (; it1 != currentNamePath.end(); ++it1) 0322 parent = stack.pop(); 0323 for (; it2 != dirs.end(); ++it2) { 0324 stack.push(parent); 0325 KActionMenu *newParent = actionCollection()->add<KActionMenu>(*it2); 0326 newParent->setText(*it2); 0327 parent->addAction(newParent); 0328 if (parent == fileImportStandardBook) 0329 toolbarImport->popupMenu()->addAction(newParent); 0330 parent = newParent; 0331 } 0332 currentNamePath = dirs; 0333 0334 QAction *book = new StandardPhraseBookInsertAction(url, (*it).name, this, SLOT(slotImportPhrasebook(QUrl)), actionCollection()); 0335 parent->addAction(book); 0336 if (parent == fileImportStandardBook) 0337 toolbarImport->popupMenu()->addAction(book); 0338 } 0339 } 0340 0341 void PhraseBookDialog::connectEditor() 0342 { 0343 connect(m_ui->lineEdit, &QLineEdit::textChanged, this, &PhraseBookDialog::slotTextChanged); 0344 connect(m_ui->noKey, &QAbstractButton::clicked, this, &PhraseBookDialog::slotNoKey); 0345 connect(m_ui->customKey, &QAbstractButton::clicked, this, &PhraseBookDialog::slotCustomKey); 0346 connect(m_ui->keyButton, &KKeySequenceWidget::keySequenceChanged, this, &PhraseBookDialog::slotKeySequenceChanged); 0347 } 0348 0349 void PhraseBookDialog::disconnectEditor() 0350 { 0351 disconnect(m_ui->lineEdit, &QLineEdit::textChanged, this, &PhraseBookDialog::slotTextChanged); 0352 disconnect(m_ui->noKey, &QAbstractButton::clicked, this, &PhraseBookDialog::slotNoKey); 0353 disconnect(m_ui->customKey, &QAbstractButton::clicked, this, &PhraseBookDialog::slotCustomKey); 0354 disconnect(m_ui->keyButton, &KKeySequenceWidget::keySequenceChanged, this, &PhraseBookDialog::slotKeySequenceChanged); 0355 } 0356 0357 void PhraseBookDialog::selectionChanged() 0358 { 0359 disconnectEditor(); 0360 bool modified = phrasebookChanged; 0361 QModelIndex selected = m_ui->treeView->selectionModel()->currentIndex(); 0362 QModelIndex shortcutIndex = selected.sibling(selected.row(), 1); 0363 QStandardItem *item = m_bookModel->itemFromIndex(selected); 0364 if (!m_ui->treeView->selectionModel()->hasSelection()) { 0365 m_ui->textLabel->setText(i18n("Text of the &phrase:")); 0366 m_ui->textLabel->setEnabled(false); 0367 m_ui->phrasebox->setEnabled(false); 0368 m_ui->lineEdit->setText(QLatin1String("")); 0369 m_ui->lineEdit->setEnabled(false); 0370 m_ui->shortcutLabel->setEnabled(false); 0371 m_ui->keyButton->clearKeySequence(); 0372 m_ui->keyButton->setEnabled(false); 0373 m_ui->noKey->setChecked(false); 0374 m_ui->noKey->setEnabled(false); 0375 m_ui->customKey->setChecked(false); 0376 m_ui->customKey->setEnabled(false); 0377 } else if (!item->isDropEnabled()) { 0378 // It's a phrase, since drop isn't enabled 0379 m_ui->textLabel->setText(i18n("Text of the &phrase:")); 0380 m_ui->textLabel->setEnabled(true); 0381 m_ui->phrasebox->setEnabled(true); 0382 m_ui->lineEdit->setText(m_bookModel->data(selected, Qt::DisplayRole).toString()); 0383 m_ui->lineEdit->setEnabled(true); 0384 m_ui->shortcutLabel->setEnabled(true); 0385 QString shortcut = m_bookModel->data(shortcutIndex, Qt::DisplayRole).toString(); 0386 m_ui->keyButton->setKeySequence(QKeySequence(shortcut)); 0387 if (shortcut.isEmpty() || shortcut.isNull()) { 0388 m_ui->noKey->setChecked(true); 0389 } else { 0390 m_ui->customKey->setChecked(true); 0391 } 0392 m_ui->keyButton->setEnabled(true); 0393 m_ui->noKey->setEnabled(true); 0394 m_ui->customKey->setEnabled(true); 0395 } else { 0396 // It's a book since drop is enabled 0397 m_ui->textLabel->setText(i18n("Name of the &phrase book:")); 0398 m_ui->textLabel->setEnabled(true); 0399 m_ui->phrasebox->setEnabled(true); 0400 m_ui->lineEdit->setText(m_bookModel->data(selected, Qt::DisplayRole).toString()); 0401 m_ui->lineEdit->setEnabled(true); 0402 m_ui->shortcutLabel->setEnabled(false); 0403 m_ui->keyButton->clearKeySequence(); // Can't have a shortcut for a book 0404 m_ui->keyButton->setEnabled(false); 0405 m_ui->noKey->setChecked(false); 0406 m_ui->noKey->setEnabled(false); 0407 m_ui->customKey->setChecked(false); 0408 m_ui->customKey->setEnabled(false); 0409 } 0410 connectEditor(); 0411 phrasebookChanged = modified; 0412 } 0413 0414 bool PhraseBookDialog::queryClose() 0415 { 0416 if (phrasebookChanged) { 0417 int answer = KMessageBox::questionTwoActionsCancel( 0418 this, 0419 i18n("<qt>There are unsaved changes.<br />Do you want to apply the changes before closing the \"phrase book\" window or discard the changes?</qt>"), 0420 i18n("Closing \"Phrase Book\" Window"), 0421 KStandardGuiItem::apply(), 0422 KStandardGuiItem::discard(), 0423 KStandardGuiItem::cancel(), 0424 QStringLiteral("AutomaticSave")); 0425 if (answer == KMessageBox::ButtonCode::PrimaryAction) { 0426 slotSave(); 0427 return true; 0428 } 0429 return (answer == KMessageBox::ButtonCode::SecondaryAction); 0430 } 0431 return true; 0432 } 0433 0434 void PhraseBookDialog::slotTextChanged(const QString &s) 0435 { 0436 QModelIndex selected = m_ui->treeView->selectionModel()->currentIndex(); 0437 QModelIndex textIndex = selected.sibling(selected.row(), kTextColumn); 0438 if (textIndex.isValid()) { 0439 m_bookModel->setData(textIndex, s); 0440 } 0441 } 0442 0443 void PhraseBookDialog::slotNoKey() 0444 { 0445 m_ui->noKey->setChecked(true); 0446 m_ui->customKey->setChecked(false); // This shouldn't be needed because of the groupbox... FIXME 0447 0448 QModelIndex selected = m_ui->treeView->selectionModel()->currentIndex(); 0449 QModelIndex shortcutIndex = selected.sibling(selected.row(), kShortcutColumn); 0450 if (shortcutIndex.isValid()) 0451 m_bookModel->setData(shortcutIndex, QString()); 0452 m_ui->keyButton->clearKeySequence(); 0453 } 0454 0455 void PhraseBookDialog::slotCustomKey() 0456 { 0457 m_ui->keyButton->captureKeySequence(); 0458 } 0459 0460 void PhraseBookDialog::slotKeySequenceChanged(const QKeySequence &sequence) 0461 { 0462 if (sequence.isEmpty()) { 0463 slotNoKey(); 0464 } else 0465 setShortcut(sequence); 0466 } 0467 0468 void PhraseBookDialog::setShortcut(const QKeySequence &sequence) 0469 { 0470 // Check whether the shortcut is valid 0471 // const QList<QKeySequence> cutList = cut.toList(); 0472 // for (int i = 0; i < cutList.count(); i++) { 0473 // const QKeySequence& seq = cutList[i]; 0474 // //const KKey& key = seq.key(0); 0475 // #ifdef __GNUC__ 0476 // #warning "kde 4 port it"; 0477 // #endif 0478 // #if 0 0479 // if (key.modFlags() == 0 && key.sym() < 0x3000 0480 // && QChar(key.sym()).isLetterOrNumber()) 0481 // { 0482 // QString s = i18n("In order to use the '%1' key as a shortcut, " 0483 // "it must be combined with the " 0484 // "Win, Alt, Ctrl, and/or Shift keys.", QChar(key.sym())); 0485 // KMessageBox::error( this, s, i18n("Invalid Shortcut Key") ); 0486 // return; 0487 // } 0488 // #endif 0489 // } 0490 QModelIndex selected = m_ui->treeView->selectionModel()->currentIndex(); 0491 QModelIndex shortcutIndex = selected.sibling(selected.row(), kShortcutColumn); 0492 if (shortcutIndex.isValid()) 0493 m_bookModel->setData(shortcutIndex, sequence.toString()); 0494 //// If key isn't already in use, 0495 // // Update display 0496 m_ui->noKey->setChecked(false); 0497 m_ui->customKey->setChecked(true); 0498 m_ui->keyButton->setKeySequence(sequence); 0499 } 0500 0501 void PhraseBookDialog::contextMenuRequested(const QPoint &pos) 0502 { 0503 QString name; 0504 if (m_ui->treeView->selectionModel()->hasSelection()) 0505 name = QStringLiteral("phrasebook_popup_sel"); 0506 else 0507 name = QStringLiteral("phrasebook_popup_nosel"); 0508 0509 QMenu *popup = (QMenu *)factory()->container(name, this); 0510 if (popup != nullptr) { 0511 popup->popup(m_ui->treeView->mapToGlobal(pos), nullptr); 0512 } 0513 } 0514 0515 void PhraseBookDialog::slotRemove() 0516 { 0517 if (m_ui->treeView->selectionModel()->hasSelection()) { 0518 QList<QModelIndex> selected = m_ui->treeView->selectionModel()->selectedRows(); 0519 std::sort(selected.begin(), selected.end()); 0520 // Iterate over the rows backwards so we don't modify the .row of any indexes in selected. 0521 for (int i = selected.size() - 1; i >= 0; --i) { 0522 QModelIndex index = selected.at(i); 0523 m_bookModel->removeRows(index.row(), 1, index.parent()); 0524 } 0525 } 0526 } 0527 0528 void PhraseBookDialog::slotCut() 0529 { 0530 slotCopy(); 0531 slotRemove(); 0532 } 0533 0534 void PhraseBookDialog::slotCopy() 0535 { 0536 const QList<QModelIndex> selected = m_ui->treeView->selectionModel()->selectedRows(); 0537 QString xml; 0538 for (const QModelIndex index : selected) { 0539 xml += serializeBook(index); 0540 } 0541 QMimeData *data = new QMimeData(); 0542 data->setText(xml); 0543 QApplication::clipboard()->setMimeData(data); 0544 } 0545 0546 void PhraseBookDialog::slotPaste() 0547 { 0548 const QMimeData *data = QApplication::clipboard()->mimeData(); 0549 QModelIndex index = m_ui->treeView->selectionModel()->currentIndex(); 0550 QStandardItem *item = m_bookModel->itemFromIndex(index); 0551 while (item != nullptr && !item->isDropEnabled()) 0552 item = item->parent(); 0553 QDomDocument document; 0554 document.setContent(data->text()); 0555 QDomNode node = document.documentElement(); 0556 deserializeBook(node, item); 0557 } 0558 0559 QModelIndex PhraseBookDialog::getCurrentParent() 0560 { 0561 QModelIndex currentIndex = m_ui->treeView->currentIndex(); 0562 QStandardItem *item = m_bookModel->itemFromIndex(currentIndex); 0563 if (item != nullptr && !item->isDropEnabled()) // If it's not a book 0564 currentIndex = currentIndex.parent(); 0565 return currentIndex; 0566 } 0567 0568 void PhraseBookDialog::focusNewItem(const QModelIndex &parent, QStandardItem *item) 0569 { 0570 m_ui->treeView->expand(parent); 0571 QModelIndex newIndex = m_bookModel->indexFromItem(item); 0572 m_ui->treeView->setCurrentIndex(newIndex); 0573 0574 m_ui->lineEdit->selectAll(); 0575 m_ui->lineEdit->setFocus(); 0576 } 0577 0578 void PhraseBookDialog::slotAddPhrasebook() 0579 { 0580 QModelIndex parentIndex = getCurrentParent(); 0581 QStandardItem *parent = m_bookModel->itemFromIndex(parentIndex); 0582 QStandardItem *item = new QStandardItem(kPhraseBookIcon, i18n("(New Phrase Book)")); 0583 QStandardItem *shortcutItem = new QStandardItem(); 0584 0585 QList<QStandardItem *> items; 0586 items << item << shortcutItem; 0587 if (parent) 0588 parent->appendRow(items); 0589 else 0590 m_bookModel->appendRow(items); 0591 focusNewItem(parentIndex, item); 0592 } 0593 0594 void PhraseBookDialog::slotAddPhrase() 0595 { 0596 QModelIndex parentIndex = getCurrentParent(); 0597 QStandardItem *parent = m_bookModel->itemFromIndex(parentIndex); 0598 QStandardItem *item = new QStandardItem(kPhraseIcon, i18n("(New Phrase)")); 0599 QStandardItem *shortcutItem = new QStandardItem(); 0600 0601 item->setDropEnabled(false); 0602 shortcutItem->setDropEnabled(false); 0603 0604 QList<QStandardItem *> items; 0605 items << item << shortcutItem; 0606 if (parent) 0607 parent->appendRow(items); 0608 else 0609 m_bookModel->appendRow(items); 0610 focusNewItem(parentIndex, item); 0611 } 0612 0613 void PhraseBookDialog::slotSave() 0614 { 0615 QString standardBook = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("standard.phrasebook")); 0616 if (!standardBook.isNull() && !standardBook.isEmpty()) { 0617 QFile file(standardBook); 0618 file.open(QIODevice::WriteOnly); 0619 file.write(serializeBook(QModelIndex()).toUtf8()); 0620 file.close(); 0621 Q_EMIT phrasebookConfirmed(); 0622 phrasebookChanged = false; 0623 fileSave->setEnabled(false); 0624 } 0625 } 0626 0627 void PhraseBookDialog::slotImportPhrasebook() 0628 { 0629 QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Import Phrasebook"), QUrl(), i18n("Phrase Books (*.phrasebook);Plain Text Files (*.txt);All Files (*)")); 0630 0631 slotImportPhrasebook(url); 0632 } 0633 0634 void PhraseBookDialog::slotImportPhrasebook(const QUrl &url) 0635 { 0636 if (!url.isEmpty()) { 0637 QModelIndex parentIndex = getCurrentParent(); 0638 QStandardItem *parentItem = m_bookModel->itemFromIndex(parentIndex); 0639 QFile file(url.toLocalFile()); 0640 if (file.open(QIODevice::ReadOnly)) { 0641 QDomDocument document; 0642 document.setContent(&file); 0643 0644 QDomNode node = document.documentElement(); 0645 QStandardItem *item = nullptr; 0646 if (node.hasAttributes()) { 0647 // It has attributes, so add it directly 0648 item = deserializeBook(node, parentItem); 0649 } else { 0650 // It has no attributes, so add all it's children 0651 QDomNodeList nodes = node.childNodes(); 0652 for (int i = 0; i < nodes.count(); ++i) { 0653 QDomNode child = nodes.at(i); 0654 item = deserializeBook(child, parentItem); 0655 } 0656 } 0657 focusNewItem(parentIndex, item); 0658 } else { 0659 qDebug() << "Unable to open file " << url.toLocalFile(); 0660 KMessageBox::error(this, i18n("There was an error loading file\n%1", url.toLocalFile())); 0661 } 0662 } 0663 } 0664 0665 void PhraseBookDialog::slotExportPhrasebook() 0666 { 0667 // Get the current book or if a phrase is selected get it's parent book to export. 0668 QModelIndex parentIndex = getCurrentParent(); 0669 QString content = kWholeBookXML.arg(serializeBook(parentIndex)); 0670 0671 QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Export Phrase Book"), QUrl(), i18n("Phrase Books (*.phrasebook)")); 0672 QFile file(url.toLocalFile()); 0673 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0674 QTextStream out(&file); 0675 out << content; 0676 file.close(); 0677 } else { 0678 KMessageBox::error(this, i18n("There was an error saving file\n%1", url.toLocalFile())); 0679 } 0680 } 0681 0682 // void PhraseBookDialog::slotPrint() 0683 //{ 0684 // if (printer == 0) { 0685 // printer = new QPrinter(); 0686 // } 0687 0688 // QPrintDialog *printDialog = KdePrint::createPrintDialog(printer, this); 0689 0690 // if (printDialog->exec()) { 0691 // PhraseBook book; 0692 // //treeView->fillBook (&book, treeView->hasSelectedItems()); 0693 0694 // book.print(printer); 0695 // } 0696 // delete printDialog; 0697 //}