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