File indexing completed on 2025-02-09 04:30:16
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org> 0004 SPDX-FileCopyrightText: 1997 Nicolas Hadacek <hadacek@kde.org> 0005 SPDX-FileCopyrightText: 1998 Matthias Ettrich <ettrich@kde.org> 0006 SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org> 0007 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0008 SPDX-FileCopyrightText: 2007 Roberto Raggi <roberto@kdevelop.org> 0009 SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com> 0010 SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz> 0011 0012 SPDX-License-Identifier: LGPL-2.0-or-later 0013 */ 0014 0015 #include "config-xmlgui.h" 0016 0017 #include "kshortcutseditor.h" 0018 0019 // The following is needed for KShortcutsEditorPrivate and QTreeWidgetHack 0020 #include "debug.h" 0021 #include "kshortcutsdialog_p.h" 0022 0023 #include <QAction> 0024 #include <QHeaderView> 0025 #include <QList> 0026 #include <QObject> 0027 #include <QPrintDialog> 0028 #include <QPrinter> 0029 #include <QTextCursor> 0030 #include <QTextDocument> 0031 #include <QTextTable> 0032 #include <QTextTableFormat> 0033 #include <QTimer> 0034 0035 #include <KConfig> 0036 #include <KConfigGroup> 0037 #if HAVE_GLOBALACCEL 0038 #include <KGlobalAccel> 0039 #endif 0040 #include "kactioncategory.h" 0041 #include "kactioncollection.h" 0042 #include <KTreeWidgetSearchLine> 0043 0044 //--------------------------------------------------------------------- 0045 // KShortcutsEditor 0046 //--------------------------------------------------------------------- 0047 0048 KShortcutsEditor::KShortcutsEditor(KActionCollection *collection, QWidget *parent, ActionTypes actionType, LetterShortcuts allowLetterShortcuts) 0049 : QWidget(parent) 0050 , d(new KShortcutsEditorPrivate(this)) 0051 { 0052 d->initGUI(actionType, allowLetterShortcuts); 0053 addCollection(collection); 0054 } 0055 0056 KShortcutsEditor::KShortcutsEditor(QWidget *parent, ActionTypes actionType, LetterShortcuts allowLetterShortcuts) 0057 : QWidget(parent) 0058 , d(new KShortcutsEditorPrivate(this)) 0059 { 0060 d->initGUI(actionType, allowLetterShortcuts); 0061 } 0062 0063 KShortcutsEditor::~KShortcutsEditor() 0064 { 0065 // reset all pending changes 0066 undo(); 0067 } 0068 0069 bool KShortcutsEditor::isModified() const 0070 { 0071 // Iterate over all items 0072 QTreeWidgetItemIterator it(d->ui.list, QTreeWidgetItemIterator::NoChildren); 0073 0074 for (; (*it); ++it) { 0075 KShortcutsEditorItem *item = dynamic_cast<KShortcutsEditorItem *>(*it); 0076 if (item && item->isModified()) { 0077 return true; 0078 } 0079 } 0080 return false; 0081 } 0082 0083 void KShortcutsEditor::clearCollections() 0084 { 0085 d->delegate->contractAll(); 0086 d->ui.list->clear(); 0087 d->actionCollections.clear(); 0088 QTimer::singleShot(0, this, &KShortcutsEditor::resizeColumns); 0089 } 0090 0091 void KShortcutsEditor::addCollection(KActionCollection *collection, const QString &title) 0092 { 0093 // KXmlGui add action collections unconditionally. If some plugin doesn't 0094 // provide actions we don't want to create empty subgroups. 0095 if (collection->isEmpty()) { 0096 return; 0097 } 0098 0099 // We add a bunch of items. Prevent the treewidget from permanently 0100 // updating. 0101 setUpdatesEnabled(false); 0102 0103 d->actionCollections.append(collection); 0104 // Forward our actionCollections to the delegate which does the conflict 0105 // checking. 0106 d->delegate->setCheckActionCollections(d->actionCollections); 0107 QString displayTitle = title; 0108 if (displayTitle.isEmpty()) { 0109 // Use the programName (Translated). 0110 displayTitle = collection->componentDisplayName(); 0111 } 0112 0113 KShortcutsEditorPrivate::HierarchyInfo hierarchy; 0114 hierarchy.root = d->ui.list->invisibleRootItem(); 0115 hierarchy.program = d->findOrMakeItem(hierarchy.root, displayTitle); 0116 hierarchy.action = nullptr; 0117 0118 // Set to remember which actions we have seen. 0119 QSet<QAction *> actionsSeen; 0120 0121 // Add all categories in their own subtree below the collections root node 0122 const QList<KActionCategory *> categories = collection->findChildren<KActionCategory *>(); 0123 for (KActionCategory *category : categories) { 0124 hierarchy.action = d->findOrMakeItem(hierarchy.program, category->text()); 0125 const auto categoryActions = category->actions(); 0126 for (QAction *action : categoryActions) { 0127 // Set a marker that we have seen this action 0128 actionsSeen.insert(action); 0129 d->addAction(action, hierarchy.action); 0130 } 0131 } 0132 0133 // The rest of the shortcuts are added as direct children of the action 0134 // collections root node 0135 const auto collectionActions = collection->actions(); 0136 for (QAction *action : collectionActions) { 0137 if (actionsSeen.contains(action)) { 0138 continue; 0139 } 0140 0141 d->addAction(action, hierarchy.program); 0142 } 0143 0144 // sort the list 0145 d->ui.list->sortItems(Name, Qt::AscendingOrder); 0146 0147 // Hide Global shortcuts columns if there are no global shortcuts 0148 d->setGlobalColumnsHidden(!d->m_hasAnyGlobalShortcuts); 0149 0150 // ...And hide local shortcuts columns if there are no local shortcuts 0151 d->setLocalColumnsHidden(!d->m_hasAnyLocalShortcuts); 0152 0153 // re-enable updating 0154 setUpdatesEnabled(true); 0155 0156 QTimer::singleShot(0, this, &KShortcutsEditor::resizeColumns); 0157 } 0158 0159 void KShortcutsEditor::importConfiguration(KConfigBase *config) 0160 { 0161 d->importConfiguration(config); 0162 } 0163 0164 void KShortcutsEditor::exportConfiguration(KConfigBase *config) const 0165 { 0166 Q_ASSERT(config); 0167 if (!config) { 0168 return; 0169 } 0170 0171 if (d->actionTypes & KShortcutsEditor::GlobalAction) { 0172 QString groupName(QStringLiteral("Global Shortcuts")); 0173 KConfigGroup group(config, groupName); 0174 for (KActionCollection *collection : std::as_const(d->actionCollections)) { 0175 collection->exportGlobalShortcuts(&group, true); 0176 } 0177 } 0178 if (d->actionTypes & ~KShortcutsEditor::GlobalAction) { 0179 QString groupName(QStringLiteral("Shortcuts")); 0180 KConfigGroup group(config, groupName); 0181 for (KActionCollection *collection : std::as_const(d->actionCollections)) { 0182 collection->writeSettings(&group, true); 0183 } 0184 } 0185 } 0186 0187 void KShortcutsEditor::writeConfiguration(KConfigGroup *config) const 0188 { 0189 for (KActionCollection *collection : std::as_const(d->actionCollections)) { 0190 collection->writeSettings(config); 0191 } 0192 } 0193 0194 // slot 0195 void KShortcutsEditor::resizeColumns() 0196 { 0197 for (int i = 0; i < d->ui.list->columnCount(); i++) { 0198 d->ui.list->resizeColumnToContents(i); 0199 } 0200 } 0201 0202 void KShortcutsEditor::save() 0203 { 0204 writeConfiguration(); 0205 // we have to call commit. If we wouldn't do that the changes would be 0206 // undone on deletion! That would lead to weird problems. Changes to 0207 // Global Shortcuts would vanish completely. Changes to local shortcuts 0208 // would vanish for this session. 0209 for (QTreeWidgetItemIterator it(d->ui.list); (*it); ++it) { 0210 if (KShortcutsEditorItem *item = dynamic_cast<KShortcutsEditorItem *>(*it)) { 0211 item->commit(); 0212 } 0213 } 0214 } 0215 0216 void KShortcutsEditor::undo() 0217 { 0218 // This function used to crash sometimes when invoked by clicking on "cancel" 0219 // with Qt 4.2.something. Apparently items were deleted too early by Qt. 0220 // It seems to work with 4.3-ish Qt versions. Keep an eye on this. 0221 for (QTreeWidgetItemIterator it(d->ui.list); (*it); ++it) { 0222 if (KShortcutsEditorItem *item = dynamic_cast<KShortcutsEditorItem *>(*it)) { 0223 item->undo(); 0224 } 0225 } 0226 } 0227 0228 // We ask the user here if there are any conflicts, as opposed to undo(). 0229 // They don't do the same thing anyway, this just not to confuse any readers. 0230 // slot 0231 void KShortcutsEditor::allDefault() 0232 { 0233 d->allDefault(); 0234 } 0235 0236 void KShortcutsEditor::printShortcuts() const 0237 { 0238 d->printShortcuts(); 0239 } 0240 0241 KShortcutsEditor::ActionTypes KShortcutsEditor::actionTypes() const 0242 { 0243 return d->actionTypes; 0244 } 0245 0246 void KShortcutsEditor::setActionTypes(ActionTypes actionTypes) 0247 { 0248 d->setActionTypes(actionTypes); 0249 } 0250 0251 //--------------------------------------------------------------------- 0252 // KShortcutsEditorPrivate 0253 //--------------------------------------------------------------------- 0254 0255 KShortcutsEditorPrivate::KShortcutsEditorPrivate(KShortcutsEditor *qq) 0256 : q(qq) 0257 , delegate(nullptr) 0258 { 0259 } 0260 0261 void KShortcutsEditorPrivate::initGUI(KShortcutsEditor::ActionTypes types, KShortcutsEditor::LetterShortcuts allowLetterShortcuts) 0262 { 0263 actionTypes = types; 0264 0265 ui.setupUi(q); 0266 q->layout()->setContentsMargins(0, 0, 0, 0); 0267 ui.searchFilter->searchLine()->setTreeWidget(ui.list); // Plug into search line 0268 ui.list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); 0269 ui.list->header()->hideSection(ShapeGesture); // mouse gestures didn't make it in time... 0270 ui.list->header()->hideSection(RockerGesture); 0271 0272 #if HAVE_GLOBALACCEL 0273 const bool hideGlobals = !(actionTypes & KShortcutsEditor::GlobalAction); 0274 #else 0275 const bool hideGlobals = true; 0276 #endif 0277 0278 if (hideGlobals) { 0279 setGlobalColumnsHidden(true); 0280 } else if (!(actionTypes & ~KShortcutsEditor::GlobalAction)) { 0281 setLocalColumnsHidden(true); 0282 } 0283 0284 // Create the Delegate. It is responsible for the KKeySeqeunceWidgets that 0285 // really change the shortcuts. 0286 delegate = new KShortcutsEditorDelegate(ui.list, allowLetterShortcuts == KShortcutsEditor::LetterShortcutsAllowed); 0287 0288 ui.list->setItemDelegate(delegate); 0289 ui.list->setSelectionBehavior(QAbstractItemView::SelectItems); 0290 ui.list->setSelectionMode(QAbstractItemView::SingleSelection); 0291 // we have our own editing mechanism 0292 ui.list->setEditTriggers(QAbstractItemView::NoEditTriggers); 0293 ui.list->setAlternatingRowColors(true); 0294 0295 // TODO listen to changes to global shortcuts 0296 QObject::connect(delegate, &KShortcutsEditorDelegate::shortcutChanged, q, [this](const QVariant &newShortcut, const QModelIndex &index) { 0297 capturedShortcut(newShortcut, index); 0298 }); 0299 // hide the editor widget chen its item becomes hidden 0300 QObject::connect(ui.searchFilter->searchLine(), &KTreeWidgetSearchLine::hiddenChanged, delegate, &KShortcutsEditorDelegate::hiddenBySearchLine); 0301 0302 ui.searchFilter->setFocus(); 0303 } 0304 0305 void KShortcutsEditorPrivate::setGlobalColumnsHidden(bool hide) 0306 { 0307 QHeaderView *header = ui.list->header(); 0308 header->setSectionHidden(GlobalPrimary, hide); 0309 header->setSectionHidden(GlobalAlternate, hide); 0310 } 0311 0312 void KShortcutsEditorPrivate::setLocalColumnsHidden(bool hide) 0313 { 0314 QHeaderView *header = ui.list->header(); 0315 header->setSectionHidden(LocalPrimary, hide); 0316 header->setSectionHidden(LocalAlternate, hide); 0317 } 0318 0319 void KShortcutsEditorPrivate::setActionTypes(KShortcutsEditor::ActionTypes types) 0320 { 0321 if (actionTypes == types) { 0322 return; 0323 } 0324 actionTypes = types; 0325 0326 // Show/hide columns based on the newly set action types 0327 setGlobalColumnsHidden(!(actionTypes & KShortcutsEditor::GlobalAction)); 0328 setLocalColumnsHidden(!(actionTypes & ~KShortcutsEditor::GlobalAction)); 0329 } 0330 0331 bool KShortcutsEditorPrivate::addAction(QAction *action, QTreeWidgetItem *parent) 0332 { 0333 // If the action name starts with unnamed- spit out a warning and ignore 0334 // it. That name will change at will and will break loading and writing 0335 QString actionName = action->objectName(); 0336 if (actionName.isEmpty() || actionName.startsWith(QLatin1String("unnamed-"))) { 0337 qCCritical(DEBUG_KXMLGUI) << "Skipping action without name " << action->text() << "," << actionName << "!"; 0338 return false; 0339 } 0340 0341 const QVariant value = action->property("isShortcutConfigurable"); 0342 if (!value.isValid() || value.toBool()) { 0343 new KShortcutsEditorItem(parent, action); 0344 0345 #if HAVE_GLOBALACCEL 0346 if (!m_hasAnyGlobalShortcuts) { // If one global action was found, skip 0347 m_hasAnyGlobalShortcuts = KGlobalAccel::self()->hasShortcut(action); 0348 } 0349 0350 if (!m_hasAnyLocalShortcuts) { // If one local action was found, skip 0351 m_hasAnyLocalShortcuts = !KGlobalAccel::self()->hasShortcut(action); 0352 } 0353 #else 0354 m_hasAnyLocalShortcuts = true; 0355 #endif 0356 0357 return true; 0358 } 0359 0360 return false; 0361 } 0362 0363 void KShortcutsEditorPrivate::allDefault() 0364 { 0365 for (QTreeWidgetItemIterator it(ui.list); (*it); ++it) { 0366 if (!(*it)->parent() || (*it)->type() != ActionItem) { 0367 continue; 0368 } 0369 0370 KShortcutsEditorItem *item = static_cast<KShortcutsEditorItem *>(*it); 0371 QAction *act = item->m_action; 0372 0373 QList<QKeySequence> defaultShortcuts = act->property("defaultShortcuts").value<QList<QKeySequence>>(); 0374 if (act->shortcuts() != defaultShortcuts) { 0375 QKeySequence primary = defaultShortcuts.isEmpty() ? QKeySequence() : defaultShortcuts.at(0); 0376 QKeySequence alternate = defaultShortcuts.size() <= 1 ? QKeySequence() : defaultShortcuts.at(1); 0377 changeKeyShortcut(item, LocalPrimary, primary); 0378 changeKeyShortcut(item, LocalAlternate, alternate); 0379 } 0380 0381 #if HAVE_GLOBALACCEL 0382 if (KGlobalAccel::self()->shortcut(act) != KGlobalAccel::self()->defaultShortcut(act)) { 0383 QList<QKeySequence> defaultShortcut = KGlobalAccel::self()->defaultShortcut(act); 0384 changeKeyShortcut(item, GlobalPrimary, primarySequence(defaultShortcut)); 0385 changeKeyShortcut(item, GlobalAlternate, alternateSequence(defaultShortcut)); 0386 } 0387 #endif 0388 } 0389 } 0390 0391 // static 0392 KShortcutsEditorItem *KShortcutsEditorPrivate::itemFromIndex(QTreeWidget *const w, const QModelIndex &index) 0393 { 0394 QTreeWidgetItem *item = static_cast<QTreeWidgetHack *>(w)->itemFromIndex(index); 0395 if (item && item->type() == ActionItem) { 0396 return static_cast<KShortcutsEditorItem *>(item); 0397 } 0398 return nullptr; 0399 } 0400 0401 QTreeWidgetItem *KShortcutsEditorPrivate::findOrMakeItem(QTreeWidgetItem *parent, const QString &name) 0402 { 0403 for (int i = 0; i < parent->childCount(); i++) { 0404 QTreeWidgetItem *child = parent->child(i); 0405 if (child->text(0) == name) { 0406 return child; 0407 } 0408 } 0409 QTreeWidgetItem *ret = new QTreeWidgetItem(parent, NonActionItem); 0410 ret->setText(0, name); 0411 ui.list->expandItem(ret); 0412 ret->setFlags(ret->flags() & ~Qt::ItemIsSelectable); 0413 return ret; 0414 } 0415 0416 // private slot 0417 void KShortcutsEditorPrivate::capturedShortcut(const QVariant &newShortcut, const QModelIndex &index) 0418 { 0419 // dispatch to the right handler 0420 if (!index.isValid()) { 0421 return; 0422 } 0423 int column = index.column(); 0424 KShortcutsEditorItem *item = itemFromIndex(ui.list, index); 0425 Q_ASSERT(item); 0426 0427 if (column >= LocalPrimary && column <= GlobalAlternate) { 0428 changeKeyShortcut(item, column, newShortcut.value<QKeySequence>()); 0429 } 0430 } 0431 0432 void KShortcutsEditorPrivate::changeKeyShortcut(KShortcutsEditorItem *item, uint column, const QKeySequence &capture) 0433 { 0434 // The keySequence we get is cleared by KKeySequenceWidget. No conflicts. 0435 if (capture == item->keySequence(column)) { 0436 return; 0437 } 0438 0439 item->setKeySequence(column, capture); 0440 Q_EMIT q->keyChange(); 0441 // force view update 0442 item->setText(column, capture.toString(QKeySequence::NativeText)); 0443 } 0444 0445 void KShortcutsEditorPrivate::importConfiguration(KConfigBase *config) 0446 { 0447 Q_ASSERT(config); 0448 if (!config) { 0449 return; 0450 } 0451 0452 KConfigGroup globalShortcutsGroup(config, QStringLiteral("Global Shortcuts")); 0453 if ((actionTypes & KShortcutsEditor::GlobalAction) && globalShortcutsGroup.exists()) { 0454 for (QTreeWidgetItemIterator it(ui.list); (*it); ++it) { 0455 if (!(*it)->parent()) { 0456 continue; 0457 } 0458 0459 KShortcutsEditorItem *item = static_cast<KShortcutsEditorItem *>(*it); 0460 const QString actionId = item->data(Id).toString(); 0461 if (!globalShortcutsGroup.hasKey(actionId)) { 0462 continue; 0463 } 0464 0465 QList<QKeySequence> sc = QKeySequence::listFromString(globalShortcutsGroup.readEntry(actionId, QString())); 0466 changeKeyShortcut(item, GlobalPrimary, primarySequence(sc)); 0467 changeKeyShortcut(item, GlobalAlternate, alternateSequence(sc)); 0468 } 0469 } 0470 0471 if (actionTypes & ~KShortcutsEditor::GlobalAction) { 0472 const KConfigGroup localShortcutsGroup(config, QStringLiteral("Shortcuts")); 0473 for (QTreeWidgetItemIterator it(ui.list); (*it); ++it) { 0474 if (!(*it)->parent()) { 0475 continue; 0476 } 0477 KShortcutsEditorItem *item = static_cast<KShortcutsEditorItem *>(*it); 0478 const QString actionId = item->data(Id).toString(); 0479 if (!localShortcutsGroup.hasKey(actionId)) { 0480 continue; 0481 } 0482 0483 QList<QKeySequence> sc = QKeySequence::listFromString(localShortcutsGroup.readEntry(actionId, QString())); 0484 changeKeyShortcut(item, LocalPrimary, primarySequence(sc)); 0485 changeKeyShortcut(item, LocalAlternate, alternateSequence(sc)); 0486 } 0487 } 0488 } 0489 0490 /*TODO for the printShortcuts function 0491 Nice to have features (which I'm not sure I can do before may due to 0492 more important things): 0493 0494 - adjust the general page borders, IMHO they're too wide 0495 0496 - add a custom printer options page that allows to filter out all 0497 actions that don't have a shortcut set to reduce this list. IMHO this 0498 should be optional as people might want to simply print all and when 0499 they find a new action that they assign a shortcut they can simply use 0500 a pen to fill out the empty space 0501 0502 - find a way to align the Main/Alternate/Global entries in the shortcuts 0503 column without adding borders. I first did this without a nested table 0504 but instead simply added 3 rows and merged the 3 cells in the Action 0505 name and description column, but unfortunately I didn't find a way to 0506 remove the borders between the 6 shortcut cells. 0507 */ 0508 void KShortcutsEditorPrivate::printShortcuts() const 0509 { 0510 // One can't print on wince 0511 #ifndef _WIN32_WCE 0512 QTreeWidgetItem *root = ui.list->invisibleRootItem(); 0513 QTextDocument doc; 0514 0515 doc.setDefaultFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); 0516 0517 QTextCursor cursor(&doc); 0518 cursor.beginEditBlock(); 0519 QTextCharFormat headerFormat; 0520 headerFormat.setProperty(QTextFormat::FontSizeAdjustment, 3); 0521 headerFormat.setFontWeight(QFont::Bold); 0522 cursor.insertText(i18nc("header for an applications shortcut list", "Shortcuts for %1", QGuiApplication::applicationDisplayName()), headerFormat); 0523 QTextCharFormat componentFormat; 0524 componentFormat.setProperty(QTextFormat::FontSizeAdjustment, 2); 0525 componentFormat.setFontWeight(QFont::Bold); 0526 QTextBlockFormat componentBlockFormat = cursor.blockFormat(); 0527 componentBlockFormat.setTopMargin(16); 0528 componentBlockFormat.setBottomMargin(16); 0529 0530 QTextTableFormat tableformat; 0531 tableformat.setHeaderRowCount(1); 0532 tableformat.setCellPadding(4.0); 0533 tableformat.setCellSpacing(0); 0534 tableformat.setBorderStyle(QTextFrameFormat::BorderStyle_Solid); 0535 tableformat.setBorder(0.5); 0536 0537 struct ColumnInfo { 0538 QString title; 0539 ColumnDesignation column; 0540 }; 0541 const ColumnInfo shortcutTitleToColumnMap[] = { 0542 {i18n("Main:"), LocalPrimary}, 0543 {i18n("Alternate:"), LocalAlternate}, 0544 {i18n("Global:"), GlobalPrimary}, 0545 {i18n("Global alternate:"), GlobalAlternate}, 0546 }; 0547 0548 for (int i = 0; i < root->childCount(); i++) { 0549 QTreeWidgetItem *item = root->child(i); 0550 cursor.insertBlock(componentBlockFormat, componentFormat); 0551 cursor.insertText(item->text(0)); 0552 0553 QTextTable *table = cursor.insertTable(1, 3); 0554 table->setFormat(tableformat); 0555 int currow = 0; 0556 0557 QTextTableCell cell = table->cellAt(currow, 0); 0558 QTextCharFormat format = cell.format(); 0559 format.setFontWeight(QFont::Bold); 0560 cell.setFormat(format); 0561 cell.firstCursorPosition().insertText(i18n("Action Name")); 0562 0563 cell = table->cellAt(currow, 1); 0564 cell.setFormat(format); 0565 cell.firstCursorPosition().insertText(i18n("Shortcuts")); 0566 0567 cell = table->cellAt(currow, 2); 0568 cell.setFormat(format); 0569 cell.firstCursorPosition().insertText(i18n("Description")); 0570 currow++; 0571 0572 for (QTreeWidgetItemIterator it(item); *it; ++it) { 0573 if ((*it)->type() != ActionItem) { 0574 continue; 0575 } 0576 0577 KShortcutsEditorItem *editoritem = static_cast<KShortcutsEditorItem *>(*it); 0578 table->insertRows(table->rows(), 1); 0579 QVariant data = editoritem->data(Name, Qt::DisplayRole); 0580 table->cellAt(currow, 0).firstCursorPosition().insertText(data.toString()); 0581 0582 QTextTable *shortcutTable = nullptr; 0583 for (const auto &[title, column] : shortcutTitleToColumnMap) { 0584 data = editoritem->data(column, Qt::DisplayRole); 0585 QString key = data.value<QKeySequence>().toString(); 0586 0587 if (!key.isEmpty()) { 0588 if (!shortcutTable) { 0589 shortcutTable = table->cellAt(currow, 1).firstCursorPosition().insertTable(1, 2); 0590 QTextTableFormat shortcutTableFormat = tableformat; 0591 shortcutTableFormat.setCellSpacing(0.0); 0592 shortcutTableFormat.setHeaderRowCount(0); 0593 shortcutTableFormat.setBorder(0.0); 0594 shortcutTable->setFormat(shortcutTableFormat); 0595 } else { 0596 shortcutTable->insertRows(shortcutTable->rows(), 1); 0597 } 0598 shortcutTable->cellAt(shortcutTable->rows() - 1, 0).firstCursorPosition().insertText(title); 0599 shortcutTable->cellAt(shortcutTable->rows() - 1, 1).firstCursorPosition().insertText(key); 0600 } 0601 } 0602 0603 QAction *action = editoritem->m_action; 0604 cell = table->cellAt(currow, 2); 0605 format = cell.format(); 0606 format.setProperty(QTextFormat::FontSizeAdjustment, -1); 0607 cell.setFormat(format); 0608 cell.firstCursorPosition().insertHtml(action->whatsThis()); 0609 0610 currow++; 0611 } 0612 cursor.movePosition(QTextCursor::End); 0613 } 0614 cursor.endEditBlock(); 0615 0616 QPrinter printer; 0617 QPrintDialog *dlg = new QPrintDialog(&printer, q); 0618 if (dlg->exec() == QDialog::Accepted) { 0619 doc.print(&printer); 0620 } 0621 delete dlg; 0622 #endif 0623 } 0624 0625 #include "moc_kshortcutseditor.cpp"