File indexing completed on 2024-12-08 04:27:18
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jean-Baptiste Mardelle <jb@kdenlive.org> 0003 SPDX-FileCopyrightText: 2014 Till Theato <root@ttill.de> 0004 SPDX-FileCopyrightText: 2020 Julius Künzel <jk.kdedev@smartlab.uber.space> 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "layoutmanagement.h" 0009 #include "core.h" 0010 #include "mainwindow.h" 0011 #include "utils/KMessageBox_KdenliveCompat.h" 0012 #include <KMessageBox> 0013 #include <QButtonGroup> 0014 #include <QDialog> 0015 #include <QDialogButtonBox> 0016 #include <QFileDialog> 0017 #include <QInputDialog> 0018 #include <QListWidget> 0019 #include <QMenu> 0020 #include <QMenuBar> 0021 #include <QVBoxLayout> 0022 0023 #include "kwidgetsaddons_version.h" 0024 #include <KColorScheme> 0025 #include <KConfigGroup> 0026 #include <KLocalizedString> 0027 #include <KSharedConfig> 0028 #include <KToolBar> 0029 #include <KXMLGUIFactory> 0030 0031 LayoutManagement::LayoutManagement(QObject *parent) 0032 : QObject(parent) 0033 { 0034 m_translatedNames = {{QStringLiteral("kdenlive_logging"), i18n("Logging")}, 0035 {QStringLiteral("kdenlive_editing"), i18n("Editing")}, 0036 {QStringLiteral("kdenlive_audio"), i18n("Audio")}, 0037 {QStringLiteral("kdenlive_effects"), i18n("Effects")}, 0038 {QStringLiteral("kdenlive_color"), i18n("Color")}}; 0039 0040 // Prepare layout actions 0041 KActionCategory *layoutActions = new KActionCategory(i18n("Layouts"), pCore->window()->actionCollection()); 0042 m_loadLayout = new KSelectAction(i18n("Load Layout"), pCore->window()->actionCollection()); 0043 pCore->window()->actionCollection()->setShortcutsConfigurable(m_loadLayout, false); 0044 0045 // Required to enable user to add the load layout action to toolbar 0046 layoutActions->addAction(QStringLiteral("load_layouts"), m_loadLayout); 0047 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 240, 0) 0048 connect(m_loadLayout, &KSelectAction::actionTriggered, this, &LayoutManagement::slotLoadLayout); 0049 #else 0050 connect(m_loadLayout, static_cast<void (KSelectAction::*)(QAction *)>(&KSelectAction::triggered), this, &LayoutManagement::slotLoadLayout); 0051 #endif 0052 0053 QAction *saveLayout = new QAction(i18n("Save Layout…"), pCore->window()->actionCollection()); 0054 layoutActions->addAction(QStringLiteral("save_layout"), saveLayout); 0055 connect(saveLayout, &QAction::triggered, this, &LayoutManagement::slotSaveLayout); 0056 0057 QAction *manageLayout = new QAction(i18n("Manage Layouts…"), pCore->window()->actionCollection()); 0058 layoutActions->addAction(QStringLiteral("manage_layout"), manageLayout); 0059 connect(manageLayout, &QAction::triggered, this, &LayoutManagement::slotManageLayouts); 0060 // Create 9 layout actions 0061 for (int i = 1; i < 10; i++) { 0062 QAction *load = new QAction(QIcon(), QString(), this); 0063 m_layoutActions << layoutActions->addAction("load_layout" + QString::number(i), load); 0064 } 0065 0066 // Dock Area Orientation 0067 QAction *rowDockAreaAction = new QAction(QIcon::fromTheme(QStringLiteral("object-rows")), i18n("Arrange Dock Areas In Rows"), this); 0068 layoutActions->addAction(QStringLiteral("horizontal_dockareaorientation"), rowDockAreaAction); 0069 connect(rowDockAreaAction, &QAction::triggered, this, &LayoutManagement::slotDockAreaRows); 0070 0071 QAction *colDockAreaAction = new QAction(QIcon::fromTheme(QStringLiteral("object-columns")), i18n("Arrange Dock Areas In Columns"), this); 0072 layoutActions->addAction(QStringLiteral("vertical_dockareaorientation"), colDockAreaAction); 0073 connect(colDockAreaAction, &QAction::triggered, this, &LayoutManagement::slotDockAreaColumns); 0074 0075 // Create layout switcher for the menu bar 0076 MainWindow *main = pCore->window(); 0077 m_container = new QWidget(main); 0078 m_containerGrp = new QButtonGroup(m_container); 0079 connect(m_containerGrp, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &LayoutManagement::activateLayout); 0080 auto *l1 = new QVBoxLayout; 0081 l1->addStretch(); 0082 m_containerLayout = new QHBoxLayout; 0083 m_containerLayout->setSpacing(0); 0084 m_containerLayout->setContentsMargins(0, 0, 0, 0); 0085 l1->addLayout(m_containerLayout); 0086 m_container->setLayout(l1); 0087 KColorScheme scheme(main->palette().currentColorGroup(), KColorScheme::Button); 0088 QColor bg = scheme.background(KColorScheme::AlternateBackground).color(); 0089 QString style = QString("padding-left: %4; padding-right: %4;background-color: rgb(%1,%2,%3);") 0090 .arg(bg.red()) 0091 .arg(bg.green()) 0092 .arg(bg.blue()) 0093 .arg(main->fontInfo().pixelSize() / 2); 0094 m_container->setStyleSheet(style); 0095 main->menuBar()->setCornerWidget(m_container, Qt::TopRightCorner); 0096 initializeLayouts(); 0097 } 0098 0099 void LayoutManagement::initializeLayouts() 0100 { 0101 if (m_loadLayout == nullptr) { 0102 return; 0103 } 0104 QString current; 0105 if (m_containerGrp->checkedButton()) { 0106 current = m_containerGrp->checkedButton()->text(); 0107 } 0108 MainWindow *main = pCore->window(); 0109 // Delete existing buttons 0110 while (auto item = m_containerLayout->takeAt(0)) { 0111 delete item->widget(); 0112 } 0113 0114 // Load default base layouts 0115 KConfig defaultConfig(QStringLiteral("kdenlivedefaultlayouts.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0116 KConfigGroup defaultOrder(&defaultConfig, "Order"); 0117 KConfigGroup defaultLayout(&defaultConfig, "Layouts"); 0118 QStringList defaultLayouts; 0119 0120 // Load User defined layouts 0121 KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdenlive-layoutsrc"), KConfig::NoCascade); 0122 KConfigGroup layoutGroup(config, "Layouts"); 0123 KConfigGroup layoutOrder(config, "Order"); 0124 // If we don't have any layout saved, check in main config file 0125 if (!layoutGroup.exists()) { 0126 config = KSharedConfig::openConfig(); 0127 KConfigGroup layoutGroup2(config, "Layouts"); 0128 if (layoutGroup2.exists()) { 0129 // Migrate to new config file 0130 layoutGroup2.copyTo(&layoutGroup); 0131 } 0132 } 0133 m_loadLayout->removeAllActions(); 0134 QStringList entries; 0135 bool addedDefault = false; 0136 if (!layoutOrder.exists()) { 0137 // This is an old or newly created config file, import defaults 0138 defaultLayouts = defaultOrder.entryMap().values(); 0139 entries = layoutGroup.keyList(); 0140 addedDefault = true; 0141 } else { 0142 // User sorted list 0143 entries = layoutOrder.entryMap().values(); 0144 } 0145 0146 // Add default layouts to user config in they don't exist 0147 for (const QString &lay : qAsConst(defaultLayouts)) { 0148 if (!entries.contains(lay)) { 0149 entries.insert(defaultLayouts.indexOf(lay), lay); 0150 layoutGroup.writeEntry(lay, defaultLayout.readEntry(lay)); 0151 addedDefault = true; 0152 } 0153 } 0154 if (addedDefault) { 0155 // Write updated order 0156 layoutOrder.deleteGroup(); 0157 int j = 1; 0158 for (const QString &entry : qAsConst(entries)) { 0159 layoutOrder.writeEntry(QString::number(j), entry); 0160 j++; 0161 } 0162 config->reparseConfiguration(); 0163 } 0164 for (int i = 1; i < 10; i++) { 0165 QString layoutName; 0166 if (i <= entries.count()) { 0167 layoutName = entries.at(i - 1); 0168 } else { 0169 break; 0170 } 0171 QAction *load = m_layoutActions.at(i - 1); 0172 if (layoutName.isEmpty()) { 0173 load->setText(QString()); 0174 load->setIcon(QIcon()); 0175 } else { 0176 load->setText(i18n("Layout %1: %2", i, translatedName(layoutName))); 0177 if (i < 6) { 0178 auto *lab = new QPushButton(translatedName(layoutName), m_container); 0179 lab->setProperty("layoutid", layoutName); 0180 lab->setFocusPolicy(Qt::NoFocus); 0181 lab->setCheckable(true); 0182 lab->setFlat(true); 0183 lab->setFont(main->menuBar()->font()); 0184 m_containerGrp->addButton(lab); 0185 m_containerLayout->addWidget(lab); 0186 if (!current.isEmpty() && current == layoutName) { 0187 lab->setChecked(true); 0188 } 0189 } 0190 } 0191 0192 load->setData(layoutName); 0193 if (!layoutName.isEmpty()) { 0194 load->setEnabled(true); 0195 m_loadLayout->addAction(load); 0196 } else { 0197 load->setEnabled(false); 0198 } 0199 } 0200 // Required to trigger a refresh of the container buttons 0201 main->menuBar()->resize(main->menuBar()->sizeHint()); 0202 } 0203 0204 void LayoutManagement::activateLayout(QAbstractButton *button) 0205 { 0206 if (!button) { 0207 return; 0208 } 0209 loadLayout(button->property("layoutid").toString(), false); 0210 } 0211 0212 void LayoutManagement::slotLoadLayout(QAction *action) 0213 { 0214 if (!action) { 0215 return; 0216 } 0217 0218 QString layoutId = action->data().toString(); 0219 if (layoutId.isEmpty()) { 0220 return; 0221 } 0222 loadLayout(layoutId, true); 0223 } 0224 0225 bool LayoutManagement::loadLayout(const QString &layoutId, bool selectButton) 0226 { 0227 KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdenlive-layoutsrc")); 0228 KConfigGroup layouts(config, "Layouts"); 0229 if (!layouts.hasKey(layoutId)) { 0230 // Error, layout not found 0231 return false; 0232 } 0233 Q_EMIT connectDocks(false); 0234 QByteArray state = QByteArray::fromBase64(layouts.readEntry(layoutId).toLatin1()); 0235 bool timelineVisible = true; 0236 if (state.startsWith("NO-TL")) { 0237 timelineVisible = false; 0238 state.remove(0, 5); 0239 } 0240 pCore->window()->centralWidget()->setHidden(!timelineVisible); 0241 // restore state disables all toolbars, so remember state 0242 QList<KToolBar *> barsList = pCore->window()->toolBars(); 0243 QMap<QString, bool> toolbarVisibility; 0244 for (auto &tb : barsList) { 0245 toolbarVisibility.insert(tb->objectName(), tb->isVisible()); 0246 } 0247 pCore->window()->processRestoreState(state); 0248 // Restore toolbar status 0249 QMapIterator<QString, bool> i(toolbarVisibility); 0250 while (i.hasNext()) { 0251 i.next(); 0252 KToolBar *tb = pCore->window()->toolBar(i.key()); 0253 if (tb) { 0254 tb->setVisible(i.value()); 0255 } 0256 } 0257 pCore->window()->tabifyBins(); 0258 Q_EMIT connectDocks(true); 0259 if (selectButton) { 0260 // Activate layout button 0261 QList<QAbstractButton *> buttons = m_containerGrp->buttons(); 0262 bool buttonFound = false; 0263 for (auto *button : qAsConst(buttons)) { 0264 if (button->property("layoutid").toString() == layoutId) { 0265 QSignalBlocker bk(m_containerGrp); 0266 button->setChecked(true); 0267 buttonFound = true; 0268 } 0269 } 0270 if (!buttonFound && m_containerGrp->checkedButton()) { 0271 m_containerGrp->setExclusive(false); 0272 m_containerGrp->checkedButton()->setChecked(false); 0273 m_containerGrp->setExclusive(true); 0274 } 0275 } 0276 Q_EMIT updateTitleBars(); 0277 return true; 0278 } 0279 0280 std::pair<QString, QString> LayoutManagement::saveLayout(const QString &layout, const QString &suggestedName) 0281 { 0282 0283 QString visibleName = translatedName(suggestedName); 0284 0285 QString layoutName = QInputDialog::getText(pCore->window(), i18nc("@title:window", "Save Layout"), i18n("Layout name:"), QLineEdit::Normal, visibleName); 0286 if (layoutName.isEmpty()) { 0287 return {nullptr, nullptr}; 0288 } 0289 0290 QString saveName; 0291 if (m_translatedNames.contains(layoutName)) { 0292 saveName = m_translatedNames.key(layoutName); 0293 } else { 0294 saveName = layoutName; 0295 } 0296 0297 KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdenlive-layoutsrc")); 0298 KConfigGroup layouts(config, "Layouts"); 0299 KConfigGroup order(config, "Order"); 0300 0301 if (layouts.hasKey(saveName)) { 0302 // Layout already exists 0303 int res = KMessageBox::questionTwoActions(pCore->window(), i18n("The layout %1 already exists. Do you want to replace it?", layoutName), {}, 0304 KStandardGuiItem::overwrite(), KStandardGuiItem::cancel()); 0305 if (res != KMessageBox::PrimaryAction) { 0306 return {nullptr, nullptr}; 0307 } 0308 } 0309 0310 layouts.writeEntry(saveName, layout); 0311 if (!order.entryMap().values().contains(saveName)) { 0312 int pos = order.keyList().constLast().toInt() + 1; 0313 order.writeEntry(QString::number(pos), saveName); 0314 } 0315 return {layoutName, saveName}; 0316 } 0317 0318 void LayoutManagement::slotSaveLayout() 0319 { 0320 QAbstractButton *button = m_containerGrp->checkedButton(); 0321 QString saveName; 0322 if (button) { 0323 saveName = button->text(); 0324 } 0325 0326 QByteArray st = pCore->window()->saveState(); 0327 if (!pCore->window()->timelineVisible()) { 0328 st.prepend("NO-TL"); 0329 } 0330 std::pair<QString, QString> names = saveLayout(st.toBase64(), saveName); 0331 0332 // Activate layout button 0333 if (names.first != nullptr) { 0334 QList<QAbstractButton *> buttons = m_containerGrp->buttons(); 0335 for (auto *button : qAsConst(buttons)) { 0336 if (button->text() == names.first) { 0337 QSignalBlocker bk(m_containerGrp); 0338 button->setChecked(true); 0339 } 0340 } 0341 } 0342 } 0343 0344 void LayoutManagement::slotManageLayouts() 0345 { 0346 KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdenlive-layoutsrc")); 0347 KConfigGroup layouts(config, "Layouts"); 0348 KConfigGroup order(config, "Order"); 0349 QStringList names = order.entryMap().values(); 0350 QString current; 0351 if (m_containerGrp->checkedButton()) { 0352 current = m_containerGrp->checkedButton()->text(); 0353 } 0354 QDialog d(pCore->window()); 0355 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); 0356 auto *l = new QVBoxLayout; 0357 d.setLayout(l); 0358 l->addWidget(new QLabel(i18n("Current Layouts"), &d)); 0359 QListWidget list(&d); 0360 list.setAlternatingRowColors(true); 0361 l->addWidget(&list); 0362 // Delete button 0363 QToolButton tb(&d); 0364 tb.setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); 0365 tb.setAutoRaise(true); 0366 connect(&tb, &QToolButton::clicked, this, [&layouts, &list]() { 0367 if (list.currentItem()) { 0368 layouts.deleteEntry(list.currentItem()->data(Qt::UserRole).toString()); 0369 delete list.currentItem(); 0370 } 0371 }); 0372 tb.setToolTip(i18n("Delete the layout.")); 0373 auto *l2 = new QHBoxLayout; 0374 l->addLayout(l2); 0375 l2->addWidget(&tb); 0376 // Up button 0377 QToolButton tb2(&d); 0378 tb2.setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); 0379 tb2.setAutoRaise(true); 0380 connect(&tb2, &QToolButton::clicked, this, [&list]() { 0381 if (list.currentItem() && list.currentRow() > 0) { 0382 int updatedRow = list.currentRow() - 1; 0383 QListWidgetItem *item = list.takeItem(list.currentRow()); 0384 list.insertItem(updatedRow, item); 0385 list.setCurrentRow(updatedRow); 0386 } 0387 }); 0388 l2->addWidget(&tb2); 0389 0390 // Down button 0391 QToolButton tb3(&d); 0392 tb3.setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); 0393 tb3.setAutoRaise(true); 0394 connect(&tb3, &QToolButton::clicked, this, [&list]() { 0395 if (list.currentItem() && list.currentRow() < list.count() - 1) { 0396 int updatedRow = list.currentRow() + 1; 0397 QListWidgetItem *item = list.takeItem(list.currentRow()); 0398 list.insertItem(updatedRow, item); 0399 list.setCurrentRow(updatedRow); 0400 } 0401 }); 0402 l2->addWidget(&tb3); 0403 0404 // Reset button 0405 QToolButton tb4(&d); 0406 tb4.setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0407 tb4.setAutoRaise(true); 0408 tb4.setToolTip(i18n("Reset")); 0409 connect(&tb4, &QToolButton::clicked, this, [this, &config, &list, &layouts, current]() { 0410 // Load default base layouts 0411 KConfig defaultConfig(QStringLiteral("kdenlivedefaultlayouts.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation); 0412 KConfigGroup defaultOrder(&defaultConfig, "Order"); 0413 KConfigGroup defaultLayout(&defaultConfig, "Layouts"); 0414 QStringList defaultLayoutNames = defaultOrder.entryMap().values(); 0415 // Get list of current layouts 0416 QStringList currentNames; 0417 for (int i = 0; i < list.count(); i++) { 0418 currentNames << list.item(i)->data(Qt::UserRole).toString(); 0419 } 0420 int pos = 0; 0421 // Reset selected layout if it is a default one 0422 if (list.currentItem()) { 0423 QString selectedName = list.currentItem()->data(Qt::UserRole).toString(); 0424 if (defaultLayoutNames.contains(selectedName)) { 0425 layouts.writeEntry(selectedName, defaultLayout.readEntry(selectedName)); 0426 if (!current.isEmpty() && selectedName == current) { 0427 config->reparseConfiguration(); 0428 loadLayout(current, false); 0429 } 0430 } 0431 } 0432 0433 // Re-add missing default layouts 0434 for (const QString &name : qAsConst(defaultLayoutNames)) { 0435 if (!currentNames.contains(name) && m_translatedNames.contains(name)) { 0436 // Insert default layout 0437 QListWidgetItem *item = new QListWidgetItem(translatedName(name)); 0438 item->setData(Qt::UserRole, name); 0439 item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); 0440 list.insertItem(pos, item); 0441 // Write layout data 0442 layouts.writeEntry(name, defaultLayout.readEntry(name)); 0443 } 0444 pos++; 0445 } 0446 }); 0447 l2->addWidget(&tb4); 0448 0449 // Import button 0450 QToolButton tb5(&d); 0451 tb5.setIcon(QIcon::fromTheme(QStringLiteral("document-import"))); 0452 tb5.setAutoRaise(true); 0453 tb5.setToolTip(i18n("Import")); 0454 connect(&tb5, &QToolButton::clicked, this, [this, &d, &list]() { 0455 QScopedPointer<QFileDialog> fd(new QFileDialog(&d, i18nc("@title:window", "Load Layout"))); 0456 fd->setMimeTypeFilters(QStringList() << QStringLiteral("application/kdenlivelayout")); 0457 fd->setFileMode(QFileDialog::ExistingFile); 0458 if (fd->exec() != QDialog::Accepted) { 0459 return; 0460 } 0461 QStringList selection = fd->selectedFiles(); 0462 QString url; 0463 if (!selection.isEmpty()) { 0464 url = selection.first(); 0465 } 0466 if (url.isEmpty()) { 0467 return; 0468 } 0469 QFile file(url); 0470 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 0471 KMessageBox::error(&d, i18n("Cannot open file %1", QUrl::fromLocalFile(url).fileName())); 0472 return; 0473 } 0474 QString state = QString::fromUtf8(file.readAll()); 0475 file.close(); 0476 0477 QFileInfo fileInfo(url); 0478 QString suggestedName(fileInfo.baseName()); 0479 0480 std::pair<QString, QString> names = saveLayout(state, suggestedName); 0481 0482 if (names.first != nullptr && names.second != nullptr && list.findItems(names.first, Qt::MatchFlag::MatchExactly).length() == 0) { 0483 auto *item = new QListWidgetItem(names.first, &list); 0484 item->setData(Qt::UserRole, names.second); 0485 item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); 0486 } 0487 }); 0488 l2->addWidget(&tb5); 0489 0490 // Export selected button 0491 QToolButton tb6(&d); 0492 tb6.setIcon(QIcon::fromTheme(QStringLiteral("document-export"))); 0493 tb6.setAutoRaise(true); 0494 tb6.setToolTip(i18n("Export selected")); 0495 connect(&tb6, &QToolButton::clicked, this, [&d, &list]() { 0496 if (!list.currentItem()) { 0497 // Error, no layout selected 0498 KMessageBox::error(&d, i18n("No layout selected")); 0499 return; 0500 } 0501 0502 QListWidgetItem *item = list.item(list.currentRow()); 0503 QString layoutId = item->data(Qt::UserRole).toString(); 0504 0505 KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdenlive-layoutsrc")); 0506 KConfigGroup layouts(config, "Layouts"); 0507 if (!layouts.hasKey(layoutId)) { 0508 // Error, layout not found 0509 KMessageBox::error(&d, i18n("Cannot find layout %1", layoutId)); 0510 return; 0511 } 0512 0513 QScopedPointer<QFileDialog> fd(new QFileDialog(&d, i18nc("@title:window", "Export Layout"))); 0514 fd->setMimeTypeFilters(QStringList() << QStringLiteral("application/kdenlivelayout")); 0515 fd->selectFile(layoutId + ".kdenlivelayout"); 0516 fd->setDefaultSuffix(QStringLiteral("kdenlivelayout")); 0517 fd->setFileMode(QFileDialog::AnyFile); 0518 fd->setAcceptMode(QFileDialog::AcceptSave); 0519 if (fd->exec() != QDialog::Accepted) { 0520 return; 0521 } 0522 QStringList selection = fd->selectedFiles(); 0523 QString url; 0524 if (!selection.isEmpty()) { 0525 url = selection.first(); 0526 } 0527 if (url.isEmpty()) { 0528 return; 0529 } 0530 QFile file(url); 0531 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0532 KMessageBox::error(&d, i18n("Cannot open file %1", QUrl::fromLocalFile(url).fileName())); 0533 return; 0534 } 0535 file.write(layouts.readEntry(layoutId).toUtf8()); 0536 file.close(); 0537 }); 0538 l2->addWidget(&tb6); 0539 0540 connect(&list, &QListWidget::currentRowChanged, this, [&list, &tb2, &tb3](int row) { 0541 tb2.setEnabled(row > 0); 0542 tb3.setEnabled(row < list.count() - 1); 0543 }); 0544 0545 l2->addStretch(); 0546 0547 // Add layouts to list 0548 for (const QString &name : qAsConst(names)) { 0549 auto *item = new QListWidgetItem(translatedName(name), &list); 0550 item->setData(Qt::UserRole, name); 0551 item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); 0552 } 0553 int ix = 0; 0554 if (!current.isEmpty()) { 0555 QList<QListWidgetItem *> res = list.findItems(current, Qt::MatchExactly); 0556 if (!res.isEmpty()) { 0557 ix = list.row(res.first()); 0558 } 0559 } 0560 list.setCurrentRow(ix); 0561 l->addWidget(buttonBox); 0562 d.connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject); 0563 d.connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept); 0564 if (d.exec() != QDialog::Accepted) { 0565 return; 0566 } 0567 // Reset order 0568 order.deleteGroup(); 0569 // Update order and new names 0570 for (int i = 0; i < list.count(); i++) { 0571 QListWidgetItem *item = list.item(i); 0572 QString layoutId = item->data(Qt::UserRole).toString(); 0573 if (m_translatedNames.contains(layoutId)) { 0574 // This is a default layout, no rename 0575 if (item->text() != translatedName(layoutId)) { 0576 // A default layout was renamed 0577 order.writeEntry(QString::number(i + 1), item->text()); 0578 layouts.writeEntry(item->text(), layouts.readEntry(layoutId)); 0579 layouts.deleteEntry(layoutId); 0580 } else { 0581 order.writeEntry(QString::number(i + 1), layoutId); 0582 } 0583 continue; 0584 } 0585 order.writeEntry(QString::number(i + 1), layoutId); 0586 if (item->text() != layoutId && !item->text().isEmpty()) { 0587 layouts.writeEntry(item->text(), layouts.readEntry(layoutId)); 0588 layouts.deleteEntry(layoutId); 0589 } 0590 } 0591 config->reparseConfiguration(); 0592 initializeLayouts(); 0593 } 0594 0595 const QString LayoutManagement::translatedName(const QString &name) 0596 { 0597 return m_translatedNames.contains(name) ? m_translatedNames.constFind(name).value() : name; 0598 } 0599 0600 void LayoutManagement::slotDockAreaRows() 0601 { 0602 // Use the corners for top and bottom DockWidgetArea 0603 pCore->window()->setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea); 0604 pCore->window()->setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea); 0605 pCore->window()->setCorner(Qt::TopLeftCorner, Qt::TopDockWidgetArea); 0606 pCore->window()->setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea); 0607 } 0608 0609 void LayoutManagement::slotDockAreaColumns() 0610 { 0611 // Use the corners for left and right DockWidgetArea 0612 pCore->window()->setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); 0613 pCore->window()->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); 0614 pCore->window()->setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); 0615 pCore->window()->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); 0616 }