1 /*
2 This file is part of the Okteta Kasten Framework, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2009, 2012 Alex Richardson <alex.richardson@gmx.de>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 #include "structureaddremovewidget.hpp"
9 #include "../structurestool.hpp"
10 #include "../structuresmanager.hpp"
11 #include "../structuredefinitionfile.hpp"
12 #include "../structlogging.hpp"
13
14 #include <QPushButton>
15 #include <QLabel>
16 #include <QLayout>
17 #include <QTreeWidget>
18 #include <QTreeWidgetItem>
19
20 #include <QRegExp>
21 #include <KLocalizedString>
22 #include <KConfigDialogManager>
23
24 using namespace Kasten;
25
StructureAddRemoveWidget(const QStringList & selected,Kasten::StructuresTool * tool,QWidget * parent)26 StructureAddRemoveWidget::StructureAddRemoveWidget(const QStringList& selected, Kasten::StructuresTool* tool, QWidget* parent)
27 : QWidget(parent)
28 , mTool(tool)
29 {
30 QHBoxLayout* baseLayout;
31 QVBoxLayout* tree1Layout;
32 QVBoxLayout* tree2Layout;
33 QVBoxLayout* leftRightLayout;
34 QVBoxLayout* upDownLayout;
35
36 baseLayout = new QHBoxLayout();
37 baseLayout->setContentsMargins(0, 0, 0, 0);
38
39 tree1Layout = new QVBoxLayout();
40 mTree1Label = new QLabel(i18nc("@info:label", "Installed structures:"), this);
41 tree1Layout->addWidget(mTree1Label);
42 mTreeAvailable = new QTreeWidget(this);
43 mTreeAvailable->setHeaderHidden(true);
44 mTreeAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection);
45 mTreeAvailable->setColumnCount(2);
46 mTreeAvailable->setColumnHidden(1, true);
47 tree1Layout->addWidget(mTreeAvailable);
48
49 tree2Layout = new QVBoxLayout();
50 mTree2Label = new QLabel(i18nc("@info:label", "Used structures:"), this);
51 tree2Layout->addWidget(mTree2Label);
52 mTreeSelected = new QTreeWidget(this);
53 mTreeSelected->setHeaderHidden(true);
54 mTreeSelected->setSelectionMode(QAbstractItemView::ExtendedSelection);
55 mTreeSelected->setColumnCount(2);
56 mTreeSelected->setColumnHidden(1, true);
57 tree2Layout->addWidget(mTreeSelected);
58
59 leftRightLayout = new QVBoxLayout();
60 leftRightLayout->addStretch();
61 mRightButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-right")), QString(), this);
62 leftRightLayout->addWidget(mRightButton);
63 mLeftButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-left")), QString(), this);
64 leftRightLayout->addWidget(mLeftButton);
65 leftRightLayout->addStretch();
66
67 upDownLayout = new QVBoxLayout();
68 upDownLayout->addStretch();
69 mUpButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-up")), QString(), this);
70 upDownLayout->addWidget(mUpButton);
71 mDownButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-down")), QString(), this);
72 upDownLayout->addWidget(mDownButton);
73 upDownLayout->addStretch();
74
75 baseLayout->addLayout(tree1Layout);
76 baseLayout->addLayout(leftRightLayout);
77 baseLayout->addLayout(tree2Layout);
78 baseLayout->addLayout(upDownLayout);
79 setLayout(baseLayout);
80
81 connect(mLeftButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveLeft);
82 connect(mRightButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveRight);
83 connect(mUpButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveUp);
84 connect(mDownButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveDown);
85
86 buildAvailableList();
87
88 // already loaded defs:
89 QRegExp regex(QStringLiteral("'(.+)':'(.+)'"));
90 for (const QString& s : selected) {
91 int pos = regex.indexIn(s);
92 if (pos > -1) {
93 QString pluginName = regex.cap(1);
94 QString structName = regex.cap(2);
95 if (structName == QLatin1String("*")) {
96 // add all of them
97 for (int i = 0; i < mTreeAvailable->topLevelItemCount(); i++) {
98 QTreeWidgetItem* avail = mTreeAvailable->topLevelItem(i);
99 if (avail->text(0) != pluginName) {
100 continue;
101 }
102 for (int i = 0; i < avail->childCount(); i++) {
103 QTreeWidgetItem* selStruct = avail->child(i);
104 QTreeWidgetItem* item = new QTreeWidgetItem(mTreeSelected,
105 QStringList { selStruct->text(0), pluginName });
106 mTreeSelected->addTopLevelItem(item);
107 }
108
109 break;
110 }
111 } else {
112 QTreeWidgetItem* item = new QTreeWidgetItem(mTreeSelected,
113 QStringList { structName, pluginName });
114 mTreeSelected->addTopLevelItem(item);
115 }
116 }
117 }
118
119 syncData();
120 }
121
122 StructureAddRemoveWidget::~StructureAddRemoveWidget() = default;
123
values() const124 QStringList StructureAddRemoveWidget::values() const
125 {
126 return mValues;
127 }
128
buildAvailableList()129 void StructureAddRemoveWidget::buildAvailableList()
130 {
131 const auto loadedDefs = mTool->manager()->structureDefs();
132 QList<QTreeWidgetItem*> availableItems;
133 for (StructureDefinitionFile* def : loadedDefs) {
134 if (!def->isValid()) {
135 continue;
136 }
137 QString pluginName = def->pluginInfo().pluginName();
138 if (!def->pluginInfo().isPluginEnabled()) {
139 continue;
140 }
141 QTreeWidgetItem* item = new QTreeWidgetItem(mTreeAvailable,
142 QStringList { def->pluginInfo().pluginName(), pluginName });
143 const auto structureNames = def->structureNames();
144 for (const QString& name : structureNames) {
145 QTreeWidgetItem* subItem = new QTreeWidgetItem(item,
146 QStringList { name, pluginName });
147 item->addChild(subItem);
148 }
149
150 availableItems.append(item);
151 }
152
153 mTreeAvailable->addTopLevelItems(availableItems);
154
155 }
156
moveLeft()157 void StructureAddRemoveWidget::moveLeft()
158 {
159 const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
160 bool changed = false;
161 for (QTreeWidgetItem* item : selected) {
162 delete mTreeSelected->takeTopLevelItem(
163 mTreeSelected->indexOfTopLevelItem(item));
164 changed = true;
165 }
166
167 if (changed) {
168 syncData();
169 }
170 }
171
moveRight()172 void StructureAddRemoveWidget::moveRight()
173 {
174 const QList<QTreeWidgetItem*> selected = mTreeAvailable->selectedItems();
175 bool changed = false;
176 for (const QTreeWidgetItem* item : selected) {
177 if (!item->parent()) {
178 continue; // maybe sometime add all subitems
179 }
180 QTreeWidgetItem* moveOver = new QTreeWidgetItem(mTreeSelected,
181 QStringList { item->text(0), item->text(1) });
182 // item name then parent name then path
183 mTreeSelected->addTopLevelItem(moveOver);
184 changed = true;
185 }
186
187 if (changed) {
188 syncData();
189 }
190
191 }
192
moveUp()193 void StructureAddRemoveWidget::moveUp()
194 {
195 const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
196 bool changed = false;
197 int firstIndex = -1;
198 for (QTreeWidgetItem* item : selected) {
199 int idx = mTreeSelected->indexOfTopLevelItem(item);
200 int newIdx = qMax(0, idx - 1);
201 mTreeSelected->insertTopLevelItem(newIdx,
202 mTreeSelected->takeTopLevelItem(idx));
203 // only first index
204 firstIndex = firstIndex == -1 ? newIdx : firstIndex;
205 }
206
207 if (changed) {
208 syncData();
209 }
210 if (firstIndex != -1) {
211 mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex));
212 }
213 }
214
moveDown()215 void StructureAddRemoveWidget::moveDown()
216 {
217 const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
218 bool changed = false;
219 int firstIndex = -1;
220 int maxItmCount = mTreeSelected->topLevelItemCount();
221 for (QTreeWidgetItem* item : selected) {
222 int idx = mTreeSelected->indexOfTopLevelItem(item);
223 int newIdx = qMin(idx + 1, maxItmCount - 1);
224 mTreeSelected->insertTopLevelItem(newIdx,
225 mTreeSelected->takeTopLevelItem(idx));
226 // only first index
227 firstIndex = firstIndex == -1 ? newIdx : firstIndex;
228 }
229
230 if (changed) {
231 syncData();
232 }
233 if (firstIndex != -1) {
234 mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex));
235 }
236 }
syncData()237 void StructureAddRemoveWidget::syncData()
238 {
239 const auto topLevelItemCount = mTreeSelected->topLevelItemCount();
240 QStringList strings;
241 strings.reserve(topLevelItemCount);
242 for (int i = 0; i < topLevelItemCount; ++i) {
243 QTreeWidgetItem* item = mTreeSelected->topLevelItem(i);
244 QString dataStr = QStringLiteral("\'%1\':\'%2\'").arg(item->text(1), item->text(0));
245 strings.append(dataStr);
246 }
247
248 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "selection changed to: " << strings;
249 mValues = strings;
250 }
251
updateAvailable()252 void StructureAddRemoveWidget::updateAvailable()
253 {
254 // rebuild available tree
255 mTreeAvailable->clear();
256 buildAvailableList();
257
258 // remove any structs that references not loaded files
259 QStringList plugins;
260 const auto loadedDefs = mTool->manager()->structureDefs();
261 for (const StructureDefinitionFile* def : loadedDefs) {
262 QString pluginName = def->pluginInfo().pluginName();
263 if (def->pluginInfo().isValid() && !def->pluginInfo().isPluginEnabled()) {
264 continue;
265 }
266 plugins << pluginName;
267 }
268
269 bool changed = false;
270 QList<QTreeWidgetItem*> toRemove;
271 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "paths = " << plugins;
272 for (int i = 0; i < mTreeSelected->topLevelItemCount(); ++i) {
273 QTreeWidgetItem* item = mTreeSelected->topLevelItem(i);
274 // text(1) is plugin name
275 if (!plugins.contains(item->text(1))) {
276 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES)
277 << "removed item: " << QStringLiteral("\'%1\':\'%2\'").arg(item->text(1),
278 item->text(0));
279
280 changed = true;
281 toRemove.append(item);
282 } else {
283 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES)
284 << "item " << QStringLiteral("\'%1\':\'%2\'").arg(item->text(1),
285 item->text(0)) << "still loaded -> keep";
286 }
287 }
288
289 for (QTreeWidgetItem* itm : qAsConst(toRemove)) {
290 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES)
291 << "item " << QStringLiteral("\'%1\':\'%2\'").arg(itm->text(1),
292 itm->text(0)) << "removed";
293 delete mTreeSelected->takeTopLevelItem(mTreeSelected->indexOfTopLevelItem(itm));
294 }
295
296 if (changed) {
297 syncData();
298 }
299 }
300