2 Copyright (C) 2010-2024 Ben Kibbey <bjk@luxsci.net>
4 This file is part of qpwmc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 #include <QStatusTipEvent>
23 #include <QColorDialog>
27 #include <QDialogButtonBox>
28 #include <QPushButton>
29 #include <QMessageBox>
31 #include <QContextMenuEvent>
34 #include <QCommonStyle>
38 #include "pwmdMainWindow.h"
39 #include "pwmdTreeWidget.h"
40 #include "pwmdGenPassDialog.h"
41 #include "applicationForm.h"
42 #include "pwmdSocketDialog.h"
43 #include "pwmdOptionsDialog.h"
44 #include "pwmdClientDialog.h"
45 #include "pwmdOpenDialog.h"
46 #include "pwmdSaveDialog.h"
47 #include "pwmdFileOptionsDialog.h"
48 #include "pwmdSaveDialog.h"
51 #include "pwmdExpireDialog.h"
52 #include "pwmdFileDialog.h"
53 #include "pwmdLineEdit.h"
54 #include "pwmdSearchDialog.h"
56 #include "pwmdAndroidJNI.h"
60 #define PwmdEventTargetAttr QEvent::User+1
61 #define PwmdEventNewElementCancel QEvent::User+2
62 #define PwmdEventNewAttributeCancel QEvent::User+3
63 #define PwmdEventDnDTargetAttr QEvent::User+4
64 #define PwmdEventRefreshElementTree QEvent::User+5
65 #define PwmdEventReloadConfig QEvent::User+6
66 #define PwmdEventOpenFileClose QEvent::User+7
67 #define PwmdEventOpenFileConfirm QEvent::User+8
68 #define PwmdEventClientListClose QEvent::User+9
69 #define PwmdEventFileOptionsClose QEvent::User+10
70 #define PwmdEventOptionsClose QEvent::User+11
71 #define PwmdEventAttrsRetrieved QEvent::User+12
72 #define PwmdEventBusy QEvent::User+13
74 /* The current tab in the content splitter. */
76 #define TabAttributes 1
79 /* Menu items and need to be in positional order. */
80 #define FileMenuOpen 0
81 #define FileMenuOpenForm 1
82 #define FileMenuClose 2
83 #define FileMenuSave 4
84 #define FileMenuSaveExt 5
85 #define ElementMenuNewRoot 0
86 #define ElementMenuNew 1
87 #define ElementMenuNewSibling 2
88 #define ElementMenuDelete 3
89 #define ElementMenuRename 4
90 #define ElementMenuFind 6
91 #define ElementMenuAdvancedFind 7
92 #define ElementMenuResolveTargets 8
93 #define ElementMenuEditContent 10
94 #define ElementMenuRefreshTree 11
95 #define ElementMenuMulti 12
96 #define ContentMenuInsert 0
97 #define ContentMenuSave 1
98 #define ContentMenuClipboard 2
99 #define ContentMenuPassword 4
100 #define ContentMenuExpiry 5
101 #define ContentMenuHidden 6
102 #define ContentMenuBase64 7
103 #define ContentMenuUpdate 9
104 #define ContentMenuRefresh 10
105 #define AttributeMenuNew 0
106 #define AttributeMenuDelete 1
107 #define AttributeMenuTarget 2
108 #define AttributeMenuUpdate 4
109 #define AttributeMenuRefresh 5
110 #define ViewMenuButtonLabels 0
111 #define ViewMenuExpandAll 2
112 #define ViewMenuClientList 4
114 /* A bitmask for enabled menu/toolbar items. Needed for a multi-selection to
115 * determine which items out of the selected items are able to perform which
117 #define ElementNewMask 0x01
118 #define ElementDeleteMask 0x02
119 #define ContentPasswordMask 0x04
120 #define ContentExpiryMask 0x08
121 #define AttributeNewMask 0x10
122 #define AttributeDeleteMask 0x20
124 static PwmdInquireData
*openInquireData
;
125 static bool reconnectSocket
;
126 static bool disconnectSocket
;
127 static bool updateOnEnter
;
128 static QLabel
*statusBarLabel
;
129 static bool incrementalSearch
;
130 static QStringList expandedItemsList
;
131 static QTreeWidgetItem
*nextElement
;
132 static QWidget
*nextTabWidget
;
133 static int hiddenContent
;
135 static bool findingElement
;
136 PwmdAndroidJNI
*androidJni
;
138 static QList
<SearchResult
*>searchResults
;
139 static SearchResult
*currentSearchResult
;
140 static bool prevSearchResult
;
141 static int releaseTimeout
;
142 static int origReleaseTimeout
;
144 static void freeSearchResults ();
146 enum { Content
, Password
, Attributes
};
148 PwmdMainWindow::PwmdMainWindow (const QString
& f
, const QString
& name
,
149 bool lock
, const QString
& path
,
150 const QString
&sock
, QWidget
* p
) :
153 qRegisterMetaType
<Pwmd::ConnectionState
> ("ConnectionState");
154 qRegisterMetaType
<gpg_error_t
>("gpg_error_t");
157 searchResultStatusBarLabel
= nullptr;
158 advancedSearchDialog
= nullptr;
159 connectedUser
= QString ();
160 dndOperation
= DndNone
;
161 newElement
= nullptr;
162 nextElement
= nullptr;
163 newAttribute
= nullptr;
164 previousElement
= nullptr;
165 oldSelectedItem
= nullptr;
166 previousRightPage
= nullptr;
167 selectedElement
= attributeElement
= nullptr;
168 targetAttributeElement
= nullptr;
169 selectedElementPath
= path
;
170 selectedAttribute
= nullptr;
171 selectedFilename
= QString ();
172 nSelectedElements
= 0;
173 previousAttributeText
= QString ();
174 copyElement
= nullptr;
175 newFilename
= nullptr;
177 clientDialog
= nullptr;
178 optionsDialog
= nullptr;
179 fileOptionsDialog
= nullptr;
180 openDialog
= nullptr;
181 _filename
= QString ();
182 cancelButton
= nullptr;
184 features
= pwmd_features ();
186 commandInquireFilename
= QString ();
189 searchAndReplace
= false;
192 readConfigSettings (_filename
, _socket
);
193 if (incrementalSearch
)
194 connect (elementToolBar
->widgetForAction (findElementAction
),
195 SIGNAL (textChanged (const QString
&)), this,
196 SLOT (slotFindTextChanged (const QString
&)));
198 statusBarLabel
= new QLabel ();
199 statusBar()->addWidget (statusBarLabel
);
204 if (!sock
.isEmpty ())
207 connect (ui
.tabWidget
, SIGNAL (currentChanged (int)), this, SLOT (slotTabChanged (int)));
208 QScroller::grabGesture(ui
.contentScrollArea
, QScroller::TouchGesture
);
209 QScroller::grabGesture(ui
.attributeScrollArea
, QScroller::TouchGesture
);
210 QScroller::grabGesture(ui
.commandScrollArea
, QScroller::TouchGesture
);
213 connect (ui
.actionOpen
, SIGNAL (triggered ()), this, SLOT (slotOpenFile ()));
214 connect (ui
.actionOpenForm
, SIGNAL (triggered ()), this, SLOT (slotOpenForm ()));
215 connect (ui
.actionClose
, SIGNAL (triggered ()), this, SLOT (slotCloseFile()));
216 connect (ui
.actionSave
, SIGNAL (triggered ()), this, SLOT (slotSaveDocument()));
217 connect (ui
.actionExtendedSave
, SIGNAL (triggered ()), this, SLOT (slotSaveExtended ()));
218 connect (ui
.actionFileOptions
, SIGNAL (triggered ()), this, SLOT (slotFileOptions()));
219 connect (ui
.actionGeneralOptions
, SIGNAL (triggered()), this, SLOT (slotGeneralOptions ()));
220 connect (ui
.actionReload
, SIGNAL (triggered ()), this, SLOT (slotReload()));
221 connect (ui
.actionQuit
, SIGNAL (triggered()), this, SLOT (close()));
224 connect (ui
.actionButtonLabels
, SIGNAL (triggered(bool)), this, SLOT (slotButtonLabels(bool)));
225 connect (ui
.actionClientList
, SIGNAL (triggered()), this, SLOT (slotClientList()));
226 connect (ui
.actionExpandAll
, SIGNAL (triggered(bool)), this, SLOT (slotExpandAll(bool)));
229 connect (ui
.actionSocketOptions
, SIGNAL (triggered()), this, SLOT (slotSocketOptions ()));
232 connect (ui
.actionNewRootElement
, SIGNAL (triggered()), this, SLOT (slotNewRootElement()));
233 connect (ui
.actionNewElement
, SIGNAL (triggered()), this, SLOT (slotNewElement()));
234 connect (ui
.actionNewSiblingElement
, SIGNAL (triggered()), this, SLOT (slotNewSiblingElement ()));
235 connect (ui
.actionDeleteElement
, SIGNAL (triggered()), this, SLOT (slotDeleteElement()));
236 connect (ui
.actionRenameElement
, SIGNAL (triggered()), this, SLOT (slotRenameElement()));
237 connect (ui
.actionFindElement
, SIGNAL (triggered()), this, SLOT (slotFindElement()));
238 connect (ui
.actionEditContentOrAttributes
, SIGNAL (triggered()), this, SLOT (slotEditContent ()));
239 fixupEditContentOrAttributes (true);
240 connect (ui
.actionResolveTargets
, SIGNAL (triggered ()), this, SLOT (slotResolveTargets ()));
241 connect (ui
.actionRefreshTree
, SIGNAL (triggered ()), this, SLOT (slotRefreshElementTree ()));
243 connect (ui
.actionToggleMulti
, SIGNAL (toggled(bool)), this, SLOT (slotToggleMultiMode(bool)));
247 ui
.textEdit
->setPwmdParent (this);
248 connect (ui
.actionInsertFile
, SIGNAL (triggered()), this, SLOT (slotInsertContent()));
249 connect (ui
.actionSaveToFile
, SIGNAL (triggered()), this, SLOT (slotSaveToFile()));
250 connect (ui
.actionCopyToClipboard
, SIGNAL (triggered ()), this, SLOT (slotCopyContentToClipboard ()));
251 connect (ui
.actionCreatePasswordAttribute
, SIGNAL (triggered()), this, SLOT (slotCreatePasswordAttribute()));
252 connect (ui
.actionChangeExpire
, SIGNAL (triggered()), this, SLOT (slotChangeExpire()));
253 connect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
254 connect (ui
.actionBase64
, SIGNAL (triggered(bool)), this, SLOT (slotToggleBase64Content(bool)));
255 connect (ui
.actionUpdateContent
, SIGNAL (triggered()), this, SLOT (slotSaveContent ()));
256 connect (ui
.actionRefreshContent
, SIGNAL (triggered()), this, SLOT (slotRefreshContent ()));
257 connect (ui
.passwordWidget
, SIGNAL (modified ()), this, SLOT (slotPasswordContentChanged ()));
260 ui
.attributeList
->setPwmdParent (this);
261 ui
.attributeContent
->setPwmdParent (this);
262 ui
.attributeList
->setItemDelegate (new PwmdListWidgetItemDelegate (ui
.attributeList
));
263 connect (ui
.attributeList
, SIGNAL (currentItemChanged (QListWidgetItem
*, QListWidgetItem
*)), this, SLOT (slotAttributeSelected (QListWidgetItem
*, QListWidgetItem
*)));
264 connect (ui
.attributeList
->itemDelegate (), SIGNAL (commitData (QWidget
*)), this, SLOT (slotConfirmNewAttribute (QWidget
*)));
265 connect (ui
.attributeList
->itemDelegate (), SIGNAL (closeEditor (QWidget
*, QAbstractItemDelegate::EndEditHint
)), this, SLOT (slotAttributeEditorClosed (QWidget
*, QAbstractItemDelegate::EndEditHint
)));
266 connect (ui
.actionNewAttribute
, SIGNAL (triggered ()), this, SLOT (slotNewAttribute()));
267 connect (ui
.actionDeleteAttribute
, SIGNAL (triggered ()), this, SLOT (slotDeleteAttribute ()));
268 connect (ui
.actionToggleTargetAttribute
, SIGNAL (triggered (bool)), this, SLOT (slotEditTargetAttributes(bool)));
269 connect (ui
.actionUpdateAttribute
, SIGNAL (triggered ()), this, SLOT (slotSaveContent()));
270 connect (ui
.actionRefreshAttributes
, SIGNAL (triggered ()), this, SLOT (slotRefreshAttributes ()));
271 QRegularExpression
rx ("^/[^/]+/(.*)$");
272 ui
.cb_searchAndReplace
->setValidator (new QRegularExpressionValidator (rx
,
273 ui
.cb_searchAndReplace
));
275 ui
.cb_searchAndReplace
->lineEdit ()->setClearButtonEnabled (true);
276 ui
.cb_searchAndReplace
->lineEdit ()->setPlaceholderText (tr ("/pattern/replace"));
277 connect (ui
.cb_searchAndReplace
->lineEdit (), SIGNAL (textChanged (const QString
&)), this,
278 SLOT (slotAttrSearchAndReplaceChanged (const QString
&)));
279 connect (ui
.cb_searchAndReplace
->lineEdit (), SIGNAL (returnPressed ()), this,
280 SLOT (slotAttrSearchAndReplace ()));
281 ui
.pb_searchAndReplace
->setIcon (QIcon (":icons/system-search-replace.svg"));
282 connect (ui
.pb_searchAndReplace
, SIGNAL (clicked ()), this,
283 SLOT (slotAttrSearchAndReplace ()));
286 connect (ui
.commandTextEdit
, SIGNAL (textChanged ()),
287 SLOT (slotCommandContentChanged ()));
288 connect (ui
.commandResultTextEdit
, SIGNAL (anchorClicked (const QUrl
&)),
289 this, SLOT (slotCommandAnchorClicked (const QUrl
&)));
290 connect (ui
.commandResultTextEdit
, SIGNAL (textChanged ()),
291 SLOT (slotCommandResultContentChanged ()));
292 connect (ui
.pb_commandSearch
, SIGNAL (clicked()), this, SLOT (slotSearchCommandResults ()));
293 connect (ui
.ck_commandInquire
, SIGNAL (stateChanged (int)), this,
294 SLOT (slotCommandInquireStateChanged (int)));
295 connect (ui
.cb_commandHistory
, SIGNAL (activated (int)), this,
296 SLOT (slotCommandHistoryChanged (int)));
297 connect (ui
.cb_commandHistory
, SIGNAL (currentIndexChanged (int)), this,
298 SLOT (slotCommandHistoryChanged (int)));
299 connect (ui
.tb_commandInquireFilename
, SIGNAL (clicked ()), this,
300 SLOT (slotCommandInquireFilename ()));
301 ui
.commandTextEdit
->setPwmdParent (this);
305 connect (ui
.actionVersion
, SIGNAL (triggered()), this, SLOT (slotVersion ()));
306 connect (ui
.actionAboutQt
, SIGNAL (triggered()), qApp
, SLOT (aboutQt ()));
308 progressBar
= new QProgressBar (ui
.statusbar
);
309 ui
.statusbar
->addPermanentWidget (progressBar
);
310 progressBar
->setHidden (true);
311 progressBar
->setAlignment (Qt::AlignHCenter
);
313 ui
.elementTree
->setPwmdParent (this);
314 ui
.elementTree
->header ()->setSectionResizeMode (0, QHeaderView::ResizeToContents
);
315 ui
.elementTree
->header ()->setStretchLastSection (false);
316 ui
.elementTree
->setItemDelegate (new PwmdTreeWidgetItemDelegate (ui
.elementTree
));
318 QAction
*act
= new QAction (ui
.elementTree
);
319 connect (act
, SIGNAL (triggered ()), this, SLOT (slotDeleteElement ()));
320 ui
.elementTree
->addAction (act
);
321 act
= new QAction (ui
.elementTree
);
322 connect (act
, SIGNAL (triggered ()), this, SLOT (slotNewElement ()));
323 ui
.elementTree
->addAction (act
);
324 act
= new QAction (ui
.elementTree
);
325 connect (act
, SIGNAL (triggered ()), this, SLOT (slotRenameElement ()));
326 ui
.elementTree
->addAction (act
);
327 act
= new QAction (ui
.elementTree
);
328 connect (act
, SIGNAL (triggered ()), this, SLOT (slotEditAttributes ()));
329 ui
.elementTree
->addAction (act
);
330 act
= new QAction (ui
.elementTree
);
331 connect (act
, SIGNAL (triggered ()), this, SLOT (slotResolveTargets ()));
332 ui
.elementTree
->addAction (act
);
333 act
= new QAction (ui
.elementTree
);
334 connect (act
, SIGNAL (triggered ()), this, SLOT (slotExecuteCommand ()));
335 ui
.elementTree
->addAction (act
);
336 act
= new QAction (ui
.elementTree
);
337 connect (act
, SIGNAL (triggered ()), this, SLOT (slotExpandElement ()));
338 ui
.elementTree
->addAction (act
);
339 act
= new QAction (ui
.elementTree
);
340 connect (act
, SIGNAL (triggered ()), this, SLOT (slotCollapseElement ()));
341 ui
.elementTree
->addAction (act
);
342 act
= new QAction (ui
.elementTree
);
343 connect (act
, SIGNAL (triggered ()), this,
344 SLOT (slotClipboardElementPath ()));
345 ui
.elementTree
->addAction (act
);
347 connect (ui
.elementTree
->itemDelegate (), SIGNAL (commitData (QWidget
*)),
348 this, SLOT (slotRenameElementUpdate (QWidget
*)));
349 connect (ui
.elementTree
->itemDelegate (),
351 (QWidget
*, QAbstractItemDelegate::EndEditHint
)), this,
352 SLOT (slotElementEditorClosed
353 (QWidget
*, QAbstractItemDelegate::EndEditHint
)));
354 connect (ui
.elementTree
,
355 SIGNAL (currentItemChanged (QTreeWidgetItem
*, QTreeWidgetItem
*)),
357 SLOT (slotElementSelected (QTreeWidgetItem
*, QTreeWidgetItem
*)));
358 connect (ui
.elementTree
,
359 SIGNAL (itemEntered (QTreeWidgetItem
*, int)),
361 SLOT (slotElementEntered(QTreeWidgetItem
*, int)));
362 connect (ui
.elementTree
,
363 SIGNAL (itemSelectionChanged ()),
365 SLOT (slotItemSelectionChanged ()));
367 connect (ui
.textEdit
, SIGNAL (textChanged ()),
368 SLOT (slotContentChanged ()));
369 connect (ui
.textEdit
, SIGNAL (modificationChanged (bool)),
370 SLOT (slotContentModified (bool)));
372 setContentItemsEnabled (true);
373 clipboardTimer
= new QTimer (this);
374 clipboardTimer
->setSingleShot (true);
375 connect (clipboardTimer
, SIGNAL (timeout ()), SLOT (slotClearClipboard ()));
376 connect (ui
.passwordWidget
, SIGNAL (clipboardTimer ()), this, SLOT (slotClipboardTimer ()));
378 releaseTimer
= new QTimer(this);
379 connect(releaseTimer
, SIGNAL(timeout()), this, SLOT(slotReleaseTimer()));
381 editTargetAttributes
= false;
382 ui
.hiddenContentFrame
->setHidden (true);
384 pwm
= new Pwmd (filename (), name
, 0, this);
385 ui
.elementTree
->setPwmdHandle (pwm
);
386 pwm
->setBadPassphraseCallback (PwmdMainWindow::badPassphraseCallback
);
387 pwm
->setBadPassphraseData (this);
388 connect (pwm
, SIGNAL (busy (int, bool)), this, SLOT (slotBusy (int, bool)));
389 if (PwmdRemoteHost::fillRemoteHost (_socket
, currentHostData
))
391 pwm
->setSocket (PwmdRemoteHost::socketUrl (currentHostData
));
392 pwm
->setConnectParameters (currentHostData
.socketArgs ());
395 pwm
->setSocket (_socket
);
397 pwm
->setLockOnOpen (lock
);
398 connect (pwm
, SIGNAL (stateChanged (Pwmd::ConnectionState
)), this,
399 SLOT (slotConnectionStateChanged (Pwmd::ConnectionState
)));
401 ui
.menubar
->setNativeMenuBar (false);
402 connect (qApp
, SIGNAL (applicationStateChanged (Qt::ApplicationState
)),
403 this, SLOT (slotApplicationStateChanged (Qt::ApplicationState
)));
404 androidAuthenticating
= false;
405 androidJni
= new PwmdAndroidJNI ();
407 qRegisterMetaType
<PwmdRemoteHost
>("PwmdRemoteHost");
408 connect (androidJni
, SIGNAL (jniAuthenticated ()), this, SLOT (slotAndroidAuthenticated ()));
409 connect (androidJni
, SIGNAL (jniConnectionResult (PwmdRemoteHost
, int)), this, SLOT (slotAndroidConnectResult (PwmdRemoteHost
, int)));
410 connect (androidJni
, SIGNAL (jniConnectionError (gpg_error_t
)), this,
411 SLOT (slotAndroidConnectionError (gpg_error_t
)));
412 connect (pwm
, SIGNAL (connectReady (PwmdRemoteHost
)), this, SLOT (slotAndroidConnectReady (PwmdRemoteHost
)));
414 connect (pwm
, SIGNAL (statusMessage (QString
, void *)), this,
415 SLOT (slotStatusMessage (QString
, void *)));
416 connect (pwm
, SIGNAL (commandResult (PwmdCommandQueueItem
*, QString
, gpg_error_t
, bool)), this, SLOT (slotCommandResult (PwmdCommandQueueItem
*, QString
, gpg_error_t
, bool)));
417 connect (pwm
, SIGNAL (knownHost (void *, const char *, const char *, size_t)), this, SLOT (slotKnownHostCallback (void *, const char *, const char *, size_t)));
419 setConnected (false);
421 if (!filename().isEmpty ())
422 QTimer::singleShot (1, this, SLOT (slotConnectSocket()));
425 PwmdMainWindow::~PwmdMainWindow ()
427 disconnect (ui
.elementTree
,
428 SIGNAL (currentItemChanged (QTreeWidgetItem
*, QTreeWidgetItem
*)),
430 SLOT (slotElementSelected (QTreeWidgetItem
*, QTreeWidgetItem
*)));
431 disconnect (ui
.elementTree
, SIGNAL (itemEntered (QTreeWidgetItem
*, int)),
432 this, SLOT (slotElementEntered(QTreeWidgetItem
*, int)));
433 disconnect (ui
.elementTree
->itemDelegate (), SIGNAL (commitData (QWidget
*)),
434 this, SLOT (slotRenameElementUpdate (QWidget
*)));
435 disconnect (ui
.elementTree
->itemDelegate (),
437 (QWidget
*, QAbstractItemDelegate::EndEditHint
)), this,
438 SLOT (slotElementEditorClosed
439 (QWidget
*, QAbstractItemDelegate::EndEditHint
)));
440 disconnect (ui
.elementTree
,
441 SIGNAL (itemSelectionChanged ()),
443 SLOT (slotItemSelectionChanged ()));
444 clearElementTree (ui
.elementTree
);
445 delete advancedSearchDialog
;
449 delete fileOptionsDialog
;
450 delete optionsDialog
;
451 delete statusBarLabel
;
455 QSettings
cfg ("qpwmc");
457 if (state
== Pwmd::Opened
)
458 cfg
.setValue ("lastOpenedFile", filename ());
460 cfg
.setValue ("lastSocket", _socket
);
461 cfg
.setValue ("geometry", saveGeometry ());
462 cfg
.setValue ("windowState", saveState ());
463 cfg
.setValue ("tabGeometry", ui
.tabSplitter
->saveState ());
464 cfg
.setValue ("attributeGeometry", ui
.attributeSplitter
->saveState ());
465 cfg
.setValue ("commandGeometry", ui
.commandSplitter
->saveState ());
467 Qt::ToolButtonStyle s
= fileToolBar
->toolButtonStyle ();
468 bool b
= s
!= Qt::ToolButtonIconOnly
;
469 cfg
.setValue ("buttonLabels", b
);
470 freeSearchResults ();
474 PwmdMainWindow::ignoreErrors (PwmdCommandQueueItem
*cmd
, bool dnd
)
476 if (!hasMultiSelection ())
479 cmd
->addError (536903681); // Permission denied
480 cmd
->addError (536871048); // Element not found
484 cmd
->addError (536903743); // ELOOP
488 cmd
->addError (536870939); // Not found
492 PwmdMainWindow::slotFindFinished ()
495 findingElement
= false;
497 if (searchResultStatusBarLabel
)
498 searchResultStatusBarLabel
->hide ();
500 fixupToolBar (elementToolBar
, ElementToolBarFind
, true);
501 findElementAction
->setVisible (false);
502 ui
.tabWidget
->setEnabled (true);
503 disconnect (ui
.elementTree
,
504 SIGNAL (itemClicked (QTreeWidgetItem
*, int)),
506 SLOT (slotElementClicked (QTreeWidgetItem
*, int)));
507 connect (ui
.elementTree
,
508 SIGNAL (itemSelectionChanged ()),
510 SLOT (slotItemSelectionChanged ()));
512 if (doSaveContent (true))
514 nextElement
= ui
.elementTree
->currentItem ();
519 ui
.elementTree
->setFocus ();
520 elementSelected (ui
.elementTree
->currentItem ());
526 while (!searchResults
.isEmpty ())
528 SearchResult
*s
= searchResults
.takeFirst ();
532 currentSearchResult
= nullptr;
536 searchResultTotal (bool index
)
540 foreach (SearchResult
*r
, searchResults
)
542 if (r
->resultType () & SearchResult::Element
)
545 if (index
&& r
== currentSearchResult
)
547 if (currentSearchResult
->curAttr () != -1)
548 n
+= currentSearchResult
->attrs ().indexOf (currentSearchResult
->curAttr ())+1;
552 n
+= r
->attrs ().count ();
559 PwmdMainWindow::findElementText (const QString
&str
, bool elements
,
560 bool attrs
, bool attrValues
)
563 QTreeWidgetItem
*currentItem
= firstSelectedItem ();
564 SearchResult
*result
= nullptr;
566 if (!searchResultStatusBarLabel
)
568 searchResultStatusBarLabel
= new QLabel
;
569 searchResultStatusBarLabel
->setAlignment (Qt::AlignRight
|Qt::AlignVCenter
);
570 searchResultStatusBarLabel
->setIndent (15);
571 statusBar()->addPermanentWidget (searchResultStatusBarLabel
);
574 foreach (QChar c
, str
)
583 QRegularExpression
rx (str
, cs
? QRegularExpression::NoPatternOption
:
584 QRegularExpression::CaseInsensitiveOption
);
585 QList
< QTreeWidgetItem
* >items
= ui
.elementTree
->findItems ("*", Qt::MatchWildcard
|Qt::MatchRecursive
);
586 if (items
.isEmpty () || !rx
.isValid ())
589 foreach (QTreeWidgetItem
*item
, items
)
592 QList
<int>attrItems
;
597 if (rx
.match (item
->text (0)).hasMatch ())
600 type
|= SearchResult::Element
;
604 if (attrs
|| attrValues
)
606 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
607 PwmdAttributeList
*alist
= data
->attributes ();
609 for (int i
= 0, t
= alist
->count (); i
< t
; i
++)
611 PwmdElementAttr
*attr
= alist
->at (i
);
612 if (attrs
&& rx
.match (attr
->name ()).hasMatch ())
615 type
|= SearchResult::Attr
;
616 if (!attrItems
.contains (i
))
617 attrItems
.append (i
);
620 if (attrValues
&& attr
->name() != "_name"
621 && rx
.match (attr
->value ()).hasMatch ())
623 type
|= SearchResult::AttrValue
;
625 if (!attrItems
.contains (i
))
626 attrItems
.append (i
);
633 SearchResult
*r
= new SearchResult (item
, type
, attrItems
);
635 searchResults
.append (r
);
636 if (item
== currentItem
)
637 currentSearchResult
= result
= r
;
640 item
->setSelected (false);
643 searchResultStatusBarLabel
->setText (QString (tr ("Result %1 of %2")).arg (searchResultTotal (true)).arg (searchResultTotal (false)));
644 int n
= searchResults
.indexOf (result
);
646 return !searchResults
.isEmpty () ? searchResults
.at (n
)->element () : nullptr;
650 PwmdMainWindow::slotFindTextChanged (const QString
&str
)
655 freeSearchResults ();
657 QTreeWidgetItem
*item
= findElementText (str
);
660 QEvent
*ev
= new QStatusTipEvent (tr ("Element text not found."));
661 QCoreApplication::postEvent (statusBar (), ev
);
662 searchResultStatusBarLabel
->setText (QString (tr ("Result %1 of %2")).arg ("0", "0"));
666 if (searchResults
.contains (currentSearchResult
))
667 setCurrentElement (item
);
669 findElementCommon (false);
673 PwmdMainWindow::findElementCommon (bool previous
)
675 searchResultStatusBarLabel
->show ();
677 if (searchResults
.isEmpty ())
679 searchResultStatusBarLabel
->setText (QString (tr ("Result %1 of %2")).arg ("0").arg (0));
680 QEvent
*ev
= new QStatusTipEvent (tr ("Element text not found."));
681 QCoreApplication::postEvent (statusBar (), ev
);
685 int n
= searchResults
.indexOf (currentSearchResult
);
687 currentSearchResult
= nullptr;
689 if (currentSearchResult
&& !currentSearchResult
->attrs ().isEmpty ())
691 int a
= currentSearchResult
->curAttr ();
696 currentSearchResult
->nextAttr ();
698 currentSearchResult
->prevAttr ();
700 a
= currentSearchResult
->curAttr ();
702 currentSearchResult
->reset ();
708 if (!previous
&& n
+1 >= searchResults
.count ())
709 currentSearchResult
= searchResults
.first ();
710 else if (previous
&& n
-1 < 0)
711 currentSearchResult
= searchResults
.last ();
713 currentSearchResult
= searchResults
.at (n
-1);
715 currentSearchResult
= searchResults
.at (n
+1);
717 if (!currentSearchResult
)
718 currentSearchResult
= !searchResults
.isEmpty () ? searchResults
.at (0) : nullptr;
720 if (!currentSearchResult
)
722 setCurrentElement (nullptr);
726 if (previous
&& !currentSearchResult
->attrs ().isEmpty ())
727 currentSearchResult
->lastAttr ();
730 searchResultStatusBarLabel
->setText (QString (tr ("Result %1 of %2")).arg (searchResultTotal (true)).arg (searchResultTotal (false)));
731 setCurrentElement (currentSearchResult
->element ());
732 QEvent
*ev
= new QStatusTipEvent (tr (""));
733 QCoreApplication::postEvent (statusBar (), ev
);
737 PwmdMainWindow::slotAdvancedSearchNext (const QString
&text
, bool elements
,
738 bool attrs
, bool attrValues
,
739 bool select
, bool previousResult
)
741 static QString previous
;
742 // Toggle of search types
743 static bool prevElements
, prevAttrs
, prevAttrValues
, prevSelect
;
746 b
|= prevElements
!= elements
, prevElements
= elements
;
747 b
|= prevAttrs
!= attrs
, prevAttrs
= attrs
;
748 b
|= prevAttrValues
!= attrValues
, prevAttrValues
= attrValues
;
749 b
|= prevSelect
!= select
, prevSelect
= select
;
750 b
|= previous
!= text
, previous
= text
;
753 freeSearchResults ();
758 if (searchResults
.isEmpty () || b
)
760 findElementText (text
, elements
, attrs
, attrValues
);
761 foreach (SearchResult
*s
, searchResults
)
762 s
->element ()->setSelected (select
);
768 findElementCommon (previousResult
);
770 if ((attrs
|| attrValues
) && currentSearchResult
&&
771 ((currentSearchResult
->resultType () & SearchResult::Attr
)
772 || currentSearchResult
->resultType () & SearchResult::AttrValue
))
773 editAttributes (false, currentSearchResult
->element ());
779 PwmdMainWindow::slotAdvancedSearchFinished (int)
781 if (searchResultStatusBarLabel
)
782 searchResultStatusBarLabel
->hide ();
784 advancedSearchDialog
->hide ();
785 ui
.tabWidget
->setEnabled (true);
786 ui
.elementTree
->setFocus ();
787 QTreeWidgetItem
*item
= firstSelectedItem ();
788 elementSelected (item
);
789 connect (ui
.elementTree
,
790 SIGNAL (itemSelectionChanged ()),
792 SLOT (slotItemSelectionChanged ()));
793 fixupMultiToolbar ();
795 ui
.actionToggleMulti
->setChecked (hasMultiSelection ());
800 PwmdMainWindow::slotAdvancedSearchAction ()
802 slotAdvancedSearch (QString ());
806 PwmdMainWindow::slotSearchShiftEnterPressed ()
808 prevSearchResult
= true;
813 PwmdMainWindow::slotAdvancedSearch (const QString
&)
815 ui
.tabWidget
->setEnabled (false);
816 if (!advancedSearchDialog
)
818 PwmdLineEdit
*w
= qobject_cast
<PwmdLineEdit
*> (elementToolBar
->widgetForAction (findElementAction
));
819 advancedSearchDialog
= new PwmdSearchDialog (this);
820 advancedSearchDialog
->setSearchText (w
->text ());
821 connect (advancedSearchDialog
,
822 SIGNAL (findNext (const QString
&, bool, bool, bool, bool, bool)),
824 SLOT (slotAdvancedSearchNext (const QString
&, bool, bool, bool, bool, bool)));
825 connect (advancedSearchDialog
, SIGNAL (finished (int)), this,
826 SLOT (slotAdvancedSearchFinished (int)));
829 advancedSearchDialog
->setIncremental (incrementalSearch
);
831 disconnect (ui
.elementTree
,
832 SIGNAL (itemClicked (QTreeWidgetItem
*, int)),
834 SLOT (slotElementClicked (QTreeWidgetItem
*, int)));
835 connect (ui
.elementTree
,
836 SIGNAL (itemClicked (QTreeWidgetItem
*, int)),
838 SLOT (slotElementClicked (QTreeWidgetItem
*, int)));
839 disconnect (ui
.elementTree
,
840 SIGNAL (itemSelectionChanged ()),
842 SLOT (slotItemSelectionChanged ()));
843 resetSelectedItems ();
844 advancedSearchDialog
->reset ();
845 advancedSearchDialog
->show ();
849 PwmdMainWindow::slotFindElement ()
851 disconnect (ui
.elementTree
,
852 SIGNAL (itemClicked (QTreeWidgetItem
*, int)),
854 SLOT (slotElementClicked (QTreeWidgetItem
*, int)));
855 connect (ui
.elementTree
,
856 SIGNAL (itemClicked (QTreeWidgetItem
*, int)),
858 SLOT (slotElementClicked (QTreeWidgetItem
*, int)));
859 disconnect (ui
.elementTree
,
860 SIGNAL (itemSelectionChanged ()),
862 SLOT (slotItemSelectionChanged ()));
863 ui
.tabWidget
->setEnabled (false);
864 PwmdLineEdit
*w
= qobject_cast
<PwmdLineEdit
*> (elementToolBar
->widgetForAction (findElementAction
));
870 qApp
->inputMethod ()->show ();
871 findingElement
= true;
874 qApp
->inputMethod ()->hide ();
879 if (!findElementAction
->isVisible ())
884 fixupToolBar (elementToolBar
, ElementToolBarFind
, true);
885 findElementAction
->setVisible (true);
886 prevSearchResult
= false;
890 if (w
->text ().isEmpty ())
892 prevSearchResult
= false;
896 findElementCommon (prevSearchResult
);
897 prevSearchResult
= false;
901 PwmdMainWindow::updateElementExpiry (long t
)
903 QTreeWidgetItem
*item
= previousElement
? previousElement
: selectedElement
;
907 if (ui
.tabWidget
->currentWidget() == ui
.contentTab
)
908 setContentItemsEnabled ();
913 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
915 date
.setSecsSinceEpoch (t
);
916 data
->addAttribute ("_expire", QString ("%1").arg (t
));
917 updateTargetAttributes (item
, "_expire", QString ("%1").arg (t
));
919 if (ui
.tabWidget
->currentWidget() == ui
.contentTab
)
920 setContentItemsEnabled ();
924 PwmdMainWindow::slotChangeExpire ()
926 doSaveContent (true);
927 if (!selectedElement
)
930 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
931 QString expire
, incr
;
934 expire
= data
->attribute ("_expire");
935 incr
= data
->attribute ("_age");
936 e
= expire
.toLong ();
939 PwmdExpireDialog
d (e
>= time (nullptr) ? e
: time (nullptr), i
, this);
940 if (d
.exec () == QDialog::Rejected
)
943 newAttribute
= nullptr;
944 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
946 if (!isElementOwner (resolveTargets (item
)))
949 data
= qvariant_cast
<PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
952 if (data
->hasAttribute ("_expire"))
953 deleteAttribute (item
, "_expire", true);
955 if (data
->hasAttribute ("_age"))
956 deleteAttribute (item
, "_age", true);
961 setNewAttribute (item
, "_expire", QString ("%1").arg (d
.expire ()),
964 setNewAttribute (item
, "_age", QString ("%1").arg (d
.increment ()),
966 else if (data
->hasAttribute ("_age"))
967 deleteAttribute (item
, "_age", true);
974 showErrorMsg (gpg_error_t rc
, const QString
&str
)
978 m
.setText (QApplication::
979 tr ("There was an error while communicating with pwmd."));
980 m
.setInformativeText (QString ("ERR %1: %2: %3").arg (rc
).arg (gpg_strsource(rc
), str
));
981 m
.setIcon (QMessageBox::Critical
);
986 PwmdMainWindow::slotCommandResult (PwmdCommandQueueItem
*item
,
987 QString result
, gpg_error_t rc
, bool queued
)
989 PwmdInquireData
*inq
= item
? item
->data () : nullptr;
990 QEvent
*ev
= nullptr;
992 releaseTimer
->stop ();
993 if (releaseTimeout
> 0)
994 releaseTimer
->start (releaseTimeout
*1000);
996 // BULK command helper result built from existing queued commands.
1003 if (item
->id () >= PwmdCmdIdMainMax
)
1009 switch (item
->id ())
1012 case PwmdCmdIdUnLock
:
1013 releaseTimer
->stop();
1015 emit
mainClientLockStateChanged (item
->id () == PwmdCmdIdLock
? true : false);
1017 case PwmdCmdIdInternalStatusError
:
1018 /* Don't do anything here. Pretend the connection is still valid so the
1019 * user has a chance to recover any cached elements. */
1020 if (state
!= Pwmd::Opened
)
1023 case PwmdCmdIdInternalConnect
:
1024 case PwmdCmdIdInternalConnectHost
:
1028 case PwmdCmdIdInternalOpen
:
1029 openFileFinalize (rc
);
1031 case PwmdCmdIdInternalGenKey
:
1032 case PwmdCmdIdInternalPassword
:
1036 case PwmdCmdIdInternalSave
:
1037 pwmd_setopt (pwm
->handle (), PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
1038 pwmd_setopt (pwm
->handle (), PWMD_OPTION_LOCAL_PINENTRY
, 0);
1042 setModified (false);
1043 setWindowModified (false);
1045 if (reconnectSocket
)
1048 QTimer::singleShot (1, this, SLOT (slotConnectSocket()));
1050 else if (disconnectSocket
)
1054 case PwmdCmdIdInternalCloseFile
:
1056 case PwmdCmdIdDndMoveElement
:
1057 dndOperation
= DndNone
;
1058 if (!rc
&& item
->isFinalItem ())
1059 dndCopyMoveElementFinalize (inq
->user ());
1060 else if (item
->isFinalItem ())
1062 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventRefreshElementTree
));
1063 QCoreApplication::postEvent (this, ev
);
1066 case PwmdCmdIdDndCopyElement
:
1067 if (rc
&& item
->isFinalItem ())
1070 selectedElement
= attributeElement
= copyElement
;
1072 ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
1073 QCoreApplication::postEvent (this, ev
);
1075 if (hasMultiSelection ())
1077 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventRefreshElementTree
));
1078 QCoreApplication::postEvent (this, ev
);
1084 newElement
= nullptr;
1085 if (item
->isFinalItem ())
1086 dndCopyMoveElementFinalize (inq
->user ());
1089 case PwmdCmdIdDndCreateTarget
:
1092 if (item
->isFinalItem ())
1094 dndOperation
= DndNone
;
1095 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventDnDTargetAttr
));
1096 QCoreApplication::postEvent (this, ev
);
1101 setAttribute (static_cast <QTreeWidgetItem
*>(inq
->userPtr ()),
1102 "_target", inq
->user ());
1103 if (item
->isFinalItem ())
1104 dndCreateTargetFinalize ();
1106 case PwmdCmdIdReload
:
1112 case PwmdCmdIdInvokingUser
:
1115 invokingUserFinalize (result
);
1118 case PwmdCmdIdCurrentUser
:
1121 currentUserFinalize (result
);
1124 case PwmdCmdIdLockTimeout
:
1126 case PwmdCmdIdCommand
:
1127 ui
.commandResultTextEdit
->clear ();
1131 ui
.commandResultTextEdit
->setPlainText (QString ("ERR %1: %2").arg(rc
).arg(gpg_strerror(rc
)));
1135 if (inq
&& inq
->userBool ())
1137 ui
.commandResultTextEdit
->setOpenLinks (true);
1138 ui
.commandResultTextEdit
->setHtml (result
);
1141 ui
.commandResultTextEdit
->setPlainText (result
);
1144 if (pwm
->state () == Pwmd::Opened
&& (!inq
|| !inq
->userBool ()))
1145 refreshElementTree ();
1147 case PwmdCmdIdGetContent
:
1148 if (rc
&& item
->checkError (rc
))
1151 if (rc
&& previousElement
&& previousElement
!= selectedElement
)
1153 if (ui
.tabWidget
->currentWidget () != ui
.commandTab
)
1155 setContentItemsEnabled (false);
1160 elementSelectedFinalize (static_cast <QTreeWidgetItem
*> (inq
->userPtr ()), result
);
1162 setCurrentElement (selectedElement
);
1164 case PwmdCmdIdNewElement
:
1167 newElementFinalize (inq
->user());
1170 selectedElement
= newElement
->parent ();
1171 ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
1172 QCoreApplication::postEvent (this, ev
);
1174 case PwmdCmdIdDeleteElement
:
1175 deleteElementFinalize (item
);
1176 if (!rc
&& item
->isFinalItem ())
1177 setCurrentElement (selectedElement
);
1179 case PwmdCmdIdRenameElement
:
1182 renameElementFinalize ();
1185 selectedElement
->setText (0, inq
->user());
1186 ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
1187 QCoreApplication::postEvent (this, ev
);
1189 case PwmdCmdIdElementTreeForm
:
1190 if (rc
&& item
->checkError (rc
))
1195 QByteArray b
= result
.toUtf8 ();
1196 openFormFinalize (b
, inq
->user (), inq
->user2 ());
1199 case PwmdCmdIdElementTree
:
1200 if (rc
&& item
->checkError (rc
))
1205 if (gpg_err_code (rc
) == GPG_ERR_ELOOP
&& inq
->userBool ()) // target
1207 QTreeWidgetItem
*user
= static_cast<QTreeWidgetItem
*> (inq
->userPtr ());
1208 rc
= deleteAttribute (user
? user
: selectedElement
, "_target");
1215 QByteArray b
= result
.toUtf8 ();
1216 refreshElementTreeFinalize (b
);
1219 case PwmdCmdIdStoreContent
:
1224 saveContentFinalize (static_cast <QTreeWidgetItem
*> (inq
->userPtr()), inq
->user(), inq
->userBool());
1225 if (inq
->isSaving (e
))
1229 setCurrentElement (selectedElement
);
1231 case PwmdCmdIdPasswordContent
:
1234 savePasswordContentFinalize (static_cast <QTreeWidgetItem
*> (inq
->userPtr()), inq
->user());
1237 setCurrentElement (selectedElement
);
1239 case PwmdCmdIdAttrContent
:
1242 AttributeFinalizeT
*attr
= static_cast <AttributeFinalizeT
*> (inq
->userPtr ());
1243 saveAttrContentFinalize (inq
->user(), attr
);
1244 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false);
1248 AttributeFinalizeT
*attr
= static_cast <AttributeFinalizeT
*> (inq
->userPtr ());
1250 if (item
->isFinalItem ())
1253 if (inq
->isSaving (e
))
1258 case PwmdCmdIdAttrNew
:
1260 AttributeFinalizeT
*attr
;
1263 attr
= static_cast <AttributeFinalizeT
*> (inq
->userPtr ());
1264 setNewAttributeFinalize (attr
, inq
->userBool());
1268 attr
= static_cast <AttributeFinalizeT
*> (inq
->userPtr ());
1269 if (attr
&& item
->isFinalItem ())
1270 ui
.attributeList
->takeItem (ui
.attributeList
->row (attr
->listItem
));
1272 delete attr
->listItem
;
1276 case PwmdCmdIdAttrDelete
:
1279 deleteAttributeFinalize (static_cast <QTreeWidgetItem
*>(inq
->userPtr ()), inq
->user());
1282 case PwmdCmdIdAttrList
:
1285 refreshAttributeListFinalize (static_cast <QTreeWidgetItem
*>(inq
->userPtr ()), result
, true, inq
->userBool ());
1288 setCurrentElement (selectedElement
);
1294 if (rc
&& item
->id () != PwmdCmdIdCommand
)
1298 if ((item
->checkError (rc
)
1299 && hasMultiSelection ()
1300 && item
->isFinalItem ())
1301 || !item
->checkError (rc
))
1303 if (item
->error () && !item
->errorString().isEmpty ())
1304 showErrorMsg (item
->error (), item
->errorString ());
1310 /* The error may have been related to the previously selected element in
1311 * a bulk command. Restore the view to the previous element. */
1312 if (previousElement
&& previousElement
!= selectedElement
)
1314 ui
.elementTree
->setCurrentItem (previousElement
);
1315 selectedElement
= previousElement
;
1321 if (hasQueuedRefreshTree ())
1322 nextElement
= nullptr;
1324 if (!pwm
->queued () && nextElement
)
1325 elementSelected (nextElement
);
1329 PwmdMainWindow::slotVersion ()
1331 QMessageBox::about (this, tr ("About QPwmc"),
1332 tr ("QPwmc version %1\nlibpwmd %2\n\n"
1333 "Copyright 2015-2024 Ben Kibbey <bjk@luxsci.net>\n"
1334 "https://gitlab.com/bjk/qpwmc").arg (QPWMC_VERSION
,
1339 PwmdMainWindow::openFormFinalize (QByteArray
&result
, const QString
&file
,
1342 QSettings
cfg ("qpwmc");
1343 cfg
.setValue ("lastFormLocation", dir
);
1346 QList
< QTreeWidgetItem
* >items
= buildElementTree (result
, false);
1347 PwmdTreeWidget
*tree
= new PwmdTreeWidget ();
1349 tree
->header ()->setSectionResizeMode (0, QHeaderView::ResizeToContents
);
1350 tree
->header ()->setStretchLastSection (false);
1351 tree
->insertTopLevelItems (0, items
);
1352 tree
->sortByColumn (0, Qt::AscendingOrder
);
1353 tree
->setHeaderHidden (true);
1354 tree
->setEditTriggers (QAbstractItemView::NoEditTriggers
);
1355 tree
->ungrabGesture(Qt::TapAndHoldGesture
);
1356 tree
->ungrabGesture(Qt::TapGesture
);
1357 tree
->setCurrentItem (findElement (elementPath (selectedElement
), 0, true,
1360 ApplicationForm
*f
= new ApplicationForm (pwm
, file
, tree
, this);
1361 if (!f
->hasError ())
1363 f
->setParent (this, Qt::Dialog
);
1364 if (f
->exec () || f
->modified ())
1367 refreshElementTree ();
1371 clearElementTree (tree
);
1377 PwmdMainWindow::slotOpenForm ()
1379 doSaveContent (true);
1380 PwmdFileDialog
d (this, tr ("Open application form"), 0, "*.xml");
1381 QSettings
cfg ("qpwmc");
1382 #ifndef Q_OS_ANDROID
1383 d
.setDirectory (cfg
.value ("lastFormLocation", "/usr/local/share/qpwmc").toString ());
1385 d
.setMimeTypeFilters (QStringList ({"text/xml"}));
1386 d
.setDirectory (cfg
.value ("lastFormLocation", "/sdcard").toString ());
1389 d
.setUpdateLastLocation (false);
1390 d
.setFileMode (QFileDialog::ExistingFile
);
1391 d
.setOption (QFileDialog::ReadOnly
);
1393 if (!d
.exec () || !d
.selectedFiles ().count ())
1396 PwmdInquireData
*inq
= new PwmdInquireData ();
1397 inq
->setUser (d
.selectedFiles ().at (0));
1398 inq
->setUser2 (d
.directory ().absolutePath ());
1399 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdElementTreeForm
,
1400 "LIST --recurse --sexp",
1401 Pwmd::inquireCallback
, inq
));
1405 PwmdMainWindow::slotFileOptionsDone (int)
1407 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventFileOptionsClose
));
1408 QCoreApplication::postEvent (this, ev
);
1412 PwmdMainWindow::slotClientLockStateChanged (bool b
)
1416 releaseTimer
->stop();
1421 emit
mainClientLockStateChanged (b
);
1425 PwmdMainWindow::slotFileOptions ()
1427 fixupToolBar (fileToolBar
, FileToolBarOpen
, false);
1429 if (!fileOptionsDialog
)
1431 fileOptionsDialog
= new PwmdFileOptionsDialog (this);
1432 connect (fileOptionsDialog
, SIGNAL (finished (int)), this, SLOT (slotFileOptionsDone (int)));
1433 connect (fileOptionsDialog
, SIGNAL (clientLockStateChanged (bool)), this, SLOT (slotClientLockStateChanged (bool)));
1436 fileOptionsDialog
->show ();
1440 PwmdMainWindow::slotButtonLabels (bool b
)
1442 setupToolBarLabels (b
);
1446 PwmdMainWindow::slotTabChanged (int n
)
1452 previousElement
= nextElement
= nullptr;
1453 disconnect (ui
.tabWidget
, SIGNAL (currentChanged (int)), this, SLOT (slotTabChanged (int)));
1454 ui
.tabWidget
->setCurrentWidget (ui
.tabWidget
->widget (last
));
1455 update
= doSaveContent (true, false, false, &which
);
1459 nextTabWidget
= ui
.tabWidget
->widget (n
);
1463 ui
.tabWidget
->setCurrentWidget (ui
.attributeTab
);
1467 ui
.tabWidget
->setCurrentWidget (ui
.contentTab
);
1473 connect (ui
.tabWidget
, SIGNAL (currentChanged (int)), this, SLOT (slotTabChanged (int)));
1479 ui
.tabWidget
->setCurrentWidget (ui
.tabWidget
->widget (n
));
1480 connect (ui
.tabWidget
, SIGNAL (currentChanged (int)), this, SLOT (slotTabChanged (int)));
1481 nextTabWidget
= nullptr;
1482 fixupEditContentOrAttributes (ui
.tabWidget
->currentWidget () != ui
.attributeTab
);
1490 editTargetAttributes
= false;
1491 ui
.actionToggleTargetAttribute
->setChecked (false);
1492 setAttributeItemsEnabled ();
1493 editAttributes (false, selectedElement
);
1496 doSaveContent (false);
1497 setCommandItemsEnabled ();
1503 fixupMultiToolbar ();
1507 PwmdMainWindow::slotEditContent ()
1509 fixupEditContentOrAttributes (true);
1510 doSaveContent (false);
1511 setContentItemsEnabled ();
1515 PwmdMainWindow::setupToolBarLabels (bool b
)
1517 fileToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1518 elementToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1519 contentToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1520 attributeToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1521 commandToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1522 passwordToolBar
->setToolButtonStyle (b
? Qt::ToolButtonTextUnderIcon
: Qt::ToolButtonIconOnly
);
1525 /* En/Dis/ables menu items. Returns whether the button is enabled when 'test'
1526 * is true or not. */
1528 PwmdMainWindow::fixupMenu (QMenu
*m
, int which
, bool enable
, int checked
,
1531 QList
<QAction
*>actions
= m
->actions();
1534 return actions
.at (which
)->isEnabled ();
1536 if (m
== ui
.menuFile
)
1541 case FileMenuOpenForm
:
1544 case FileMenuSaveExt
:
1545 actions
.at (which
)->setEnabled (enable
);
1551 else if (m
== ui
.menuElement
)
1555 case ElementMenuNew
:
1556 case ElementMenuDelete
:
1557 case ElementMenuRename
:
1558 case ElementMenuFind
:
1559 case ElementMenuAdvancedFind
:
1560 actions
.at (which
)->setEnabled (enable
);
1566 else if (m
== ui
.menuContent
)
1570 case ContentMenuInsert
:
1571 case ContentMenuSave
:
1572 case ContentMenuClipboard
:
1573 case ContentMenuHidden
:
1574 case ContentMenuBase64
:
1575 case ContentMenuUpdate
:
1576 case ContentMenuPassword
:
1577 case ContentMenuRefresh
:
1578 case ContentMenuExpiry
:
1579 actions
.at (which
)->setEnabled (enable
);
1585 else if (m
== ui
.menuAttributes
)
1589 case AttributeMenuTarget
:
1590 actions
.at (which
)->setEnabled (enable
);
1593 actions
.at (which
)->setChecked (checked
);
1595 case AttributeMenuNew
:
1596 case AttributeMenuDelete
:
1597 case AttributeMenuUpdate
:
1598 case AttributeMenuRefresh
:
1599 actions
.at (which
)->setEnabled (enable
);
1605 else if (m
== ui
.menuView
)
1609 case ViewMenuButtonLabels
:
1610 case ViewMenuExpandAll
:
1611 case ViewMenuClientList
:
1612 actions
.at (which
)->setEnabled (enable
);
1622 /* En/Dis/ables toolbar buttons. Returns whether the button is enabled when
1623 * 'test' is true or not. */
1625 PwmdMainWindow::fixupToolBar (QToolBar
*t
, int which
, bool enable
, bool test
,
1628 QList
<QAction
*> list
= t
->actions ();
1629 QWidget
*w
= nullptr;
1631 for (int i
= 0; i
< list
.size(); i
++)
1633 if (t
== fileToolBar
&& which
== i
)
1635 w
= fileToolBar
->widgetForAction (list
.at (i
));
1640 return w
->isEnabled ();
1644 case FileToolBarOpen
:
1645 fixupMenu (ui
.menuFile
, FileMenuOpen
, enable
);
1646 w
->setEnabled (enable
);
1648 case FileToolBarSave
:
1649 fixupMenu (ui
.menuFile
, FileMenuSave
, enable
);
1650 w
->setEnabled (enable
);
1656 else if (t
== elementToolBar
&& which
== i
)
1658 w
= elementToolBar
->widgetForAction (list
.at (i
));
1663 return w
->isEnabled ();
1667 case ElementToolBarCreate
:
1668 fixupMenu (ui
.menuElement
, ElementMenuNew
, enable
);
1669 w
->setEnabled (enable
);
1671 case ElementToolBarDelete
:
1672 fixupMenu (ui
.menuElement
, ElementMenuDelete
, enable
);
1673 w
->setEnabled (enable
);
1675 case ElementToolBarRename
:
1676 fixupMenu (ui
.menuElement
, ElementMenuRename
, enable
);
1677 w
->setEnabled (enable
);
1679 case ElementToolBarFind
:
1680 fixupMenu (ui
.menuElement
, ElementMenuFind
, enable
);
1681 fixupMenu (ui
.menuElement
, ElementMenuAdvancedFind
, enable
);
1682 w
->setEnabled (enable
);
1683 findElementWidget
->setEnabled (enable
);
1688 else if (t
== contentToolBar
&& which
== i
)
1690 w
= contentToolBar
->widgetForAction (list
.at (i
));
1695 return w
->isEnabled ();
1699 case ContentToolBarOk
:
1700 fixupMenu (ui
.menuContent
, ContentMenuUpdate
, enable
);
1701 w
->setEnabled (enable
);
1703 case ContentToolBarPassword
:
1704 fixupMenu (ui
.menuContent
, ContentMenuPassword
, enable
);
1705 w
->setEnabled (enable
);
1707 case ContentToolBarExpiry
:
1708 fixupMenu (ui
.menuContent
, ContentMenuExpiry
, enable
);
1709 w
->setEnabled (enable
);
1711 case ContentToolBarSave
:
1712 fixupMenu (ui
.menuContent
, ContentMenuSave
, enable
);
1713 w
->setEnabled (enable
);
1715 case ContentToolBarInsert
:
1716 fixupMenu (ui
.menuContent
, ContentMenuInsert
, enable
);
1717 w
->setEnabled (enable
);
1719 case ContentToolBarRefresh
:
1720 fixupMenu (ui
.menuContent
, ContentMenuRefresh
, enable
);
1721 w
->setEnabled (enable
);
1727 else if (t
== passwordToolBar
&& which
== i
)
1729 w
= passwordToolBar
->widgetForAction (list
.at (i
));
1734 return w
->isEnabled ();
1738 case PasswordToolBarOk
:
1739 if (!ui
.passwordWidget
->isHidden ())
1741 fixupMenu (ui
.menuContent
, ContentMenuUpdate
, enable
);
1742 w
->setEnabled (enable
);
1745 case PasswordToolBarInsert
:
1746 case PasswordToolBarSave
:
1747 case PasswordToolBarExpiry
:
1748 case PasswordToolBarRefresh
:
1749 w
->setEnabled (enable
);
1755 else if (t
== attributeToolBar
&& which
== i
)
1757 w
= attributeToolBar
->widgetForAction (list
.at (i
));
1762 return w
->isEnabled ();
1766 case AttributeToolBarNew
:
1767 fixupMenu (ui
.menuAttributes
, AttributeMenuNew
, enable
);
1768 w
->setEnabled (enable
);
1770 case AttributeToolBarDelete
:
1771 fixupMenu (ui
.menuAttributes
, AttributeMenuDelete
, enable
);
1772 w
->setEnabled (enable
);
1774 case AttributeToolBarOk
:
1775 fixupMenu (ui
.menuAttributes
, AttributeMenuUpdate
, enable
);
1776 w
->setEnabled (enable
);
1778 case AttributeToolBarRefresh
:
1779 fixupMenu (ui
.menuAttributes
, AttributeMenuRefresh
, enable
);
1780 w
->setEnabled (enable
);
1786 else if (t
== commandToolBar
&& which
== i
)
1788 w
= commandToolBar
->widgetForAction (list
.at (i
));
1793 return w
->isEnabled ();
1797 case CommandToolBarSave
:
1798 case CommandToolBarClear
:
1799 case CommandToolBarOk
:
1800 case CommandToolBarRefresh
:
1801 case CommandToolBarHelp
:
1802 w
->setEnabled (enable
);
1813 void PwmdMainWindow::slotCommandInquireFilename ()
1815 PwmdFileDialog
d (this, tr ("Inquire data from file"));
1817 d
.setFileMode (QFileDialog::ExistingFile
);
1818 d
.setOption (QFileDialog::ReadOnly
);
1820 if (!d
.exec () || !d
.selectedFiles ().count ())
1823 setCommandInquireFilename (d
.selectedFiles ().at (0));
1826 void PwmdMainWindow::slotCommandInquireStateChanged (int s
)
1828 bool b
= s
== Qt::Unchecked
? false : true;
1830 ui
.le_commandInquire
->setEnabled (b
);
1831 ui
.tb_commandInquireFilename
->setEnabled (b
);
1832 setCommandInquireFilename (QString ());
1836 PwmdMainWindow::slotSearchCommandResults ()
1838 if (ui
.le_commandSearch
->text ().isEmpty ())
1841 ui
.commandResultTextEdit
->find (ui
.le_commandSearch
->text ());
1845 PwmdMainWindow::slotClearCommand ()
1847 ui
.commandTextEdit
->clear ();
1848 setCommandInquireFilename (QString ());
1849 ui
.commandResultTextEdit
->clear ();
1850 ui
.ck_commandInquire
->setChecked (false);
1851 ui
.le_commandInquire
->setText ("");
1852 ui
.le_commandInquire
->setEnabled (false);
1853 ui
.le_commandSearch
->setText ("");
1854 ui
.le_commandSearch
->setEnabled (false);
1855 ui
.pb_commandSearch
->setEnabled (false);
1859 PwmdMainWindow::slotSaveCommandResult ()
1861 PwmdFileDialog
d (this, tr ("Save command result"));
1863 d
.setAcceptMode (QFileDialog::AcceptSave
);
1864 d
.setFileMode (QFileDialog::AnyFile
);
1866 if (!d
.exec () || d
.selectedFiles ().isEmpty ())
1869 QStringList f
= d
.selectedFiles ();
1870 QFile
file (f
.at (0));
1872 if (!file
.open (QFile::WriteOnly
))
1876 m
.setText (file
.fileName ());
1877 m
.setInformativeText (file
.errorString ());
1878 m
.setIcon (QMessageBox::Warning
);
1883 if (file
.write (ui
.commandResultTextEdit
->document ()->toPlainText ().toUtf8 ()) ==
1888 m
.setText (file
.fileName ());
1889 m
.setInformativeText (file
.errorString ());
1890 m
.setIcon (QMessageBox::Warning
);
1896 PwmdMainWindow::slotCommandHelp ()
1898 PwmdInquireData
*inq
= new PwmdInquireData ();
1899 PwmdCommandQueueItem
*item
= new PwmdCommandQueueItem (PwmdCmdIdCommand
,
1900 "HELP --html", 0, inq
);
1902 inq
->setUserBool (true);
1903 pwm
->command (item
);
1907 PwmdMainWindow::slotCommandAnchorClicked (const QUrl
&url
)
1909 QString cmd
= QString ("HELP --html %1").arg (url
.path ());
1910 PwmdInquireData
*inq
= new PwmdInquireData ();
1911 PwmdCommandQueueItem
*item
= new PwmdCommandQueueItem (PwmdCmdIdCommand
, cmd
,
1914 inq
->setUserBool (true);
1915 pwm
->command (item
);
1919 PwmdMainWindow::slotCommandResultContentChanged ()
1921 bool b
= ui
.commandResultTextEdit
->document ()->characterCount () > 1;
1923 fixupToolBar (commandToolBar
, CommandToolBarSave
, b
);
1924 ui
.commandResultTextEdit
->setEnabled (b
);
1925 ui
.le_commandSearch
->setEnabled (b
);
1926 ui
.pb_commandSearch
->setEnabled (b
);
1930 PwmdMainWindow::slotCommandContentChanged ()
1932 tabify (ui
.commandTextEdit
);
1933 bool b
= ui
.commandTextEdit
->toPlainText ().length();
1934 fixupToolBar (commandToolBar
, CommandToolBarOk
, b
);
1935 fixupToolBar (commandToolBar
, CommandToolBarClear
, b
);
1939 PwmdMainWindow::setCommandInquireFilename (const QString
&s
)
1942 ui
.commandTextEdit
->setPlaceholderText ("");
1944 ui
.commandTextEdit
->setPlaceholderText(QString (tr ("Inquire data obtained from file %1")).arg (s
));
1946 ui
.commandTextEdit
->setEnabled (s
.isEmpty ());
1947 commandInquireFilename
= s
;
1949 ui
.commandTextEdit
->document ()->setPlainText ("");
1951 ui
.tb_commandInquireFilename
->setEnabled (ui
.ck_commandInquire
->isChecked ());
1952 fixupToolBar (commandToolBar
, CommandToolBarOk
, !s
.isEmpty ()
1953 || !ui
.commandTextEdit
->document ()->toPlainText ().isEmpty ());
1957 PwmdMainWindow::slotCommandHistoryChanged (int idx
)
1962 PwmdCommandHistoryData
*data
= qvariant_cast
<PwmdCommandHistoryData
*> (ui
.cb_commandHistory
->currentData ());
1966 ui
.commandTextEdit
->setPlainText (data
->args ());
1967 ui
.ck_commandInquire
->setChecked (data
->isInquire ());
1968 ui
.le_commandInquire
->setText (data
->inquireCmd ());
1969 setCommandInquireFilename (data
->inquireFilename ());
1973 PwmdMainWindow::slotExecuteCommand ()
1975 QString str
= ui
.commandTextEdit
->toPlainText ().replace ("<TAB>", "\t", Qt::CaseInsensitive
);
1977 ui
.commandResultTextEdit
->setPlainText ("");
1979 if (str
.isEmpty () &&
1980 (!ui
.ck_commandInquire
->isChecked () ||
1981 (ui
.ck_commandInquire
->isChecked () && ui
.le_commandInquire
->text ().isEmpty ())))
1985 for (int i
= 0; i
< ui
.cb_commandHistory
->count (); i
++)
1987 PwmdCommandHistoryData
*data
= qvariant_cast
<PwmdCommandHistoryData
*> (ui
.cb_commandHistory
->itemData (i
));
1988 if (data
&& ui
.ck_commandInquire
->isChecked () == data
->isInquire ()
1989 && ui
.le_commandInquire
->text () == data
->inquireCmd ()
1990 && ui
.commandTextEdit
->toPlainText () == data
->args ())
1995 else if (data
&& !commandInquireFilename
.isEmpty ()
1996 && ui
.ck_commandInquire
->isChecked () == data
->isInquire ()
1997 && ui
.le_commandInquire
->text () == data
->inquireCmd ()
1998 && commandInquireFilename
== data
->inquireFilename ())
2007 PwmdCommandHistoryData
*data
= new PwmdCommandHistoryData (ui
.commandTextEdit
->toPlainText (), ui
.ck_commandInquire
->isChecked (), ui
.le_commandInquire
->text (), commandInquireFilename
);
2008 if (!commandInquireFilename
.isEmpty ())
2009 ui
.cb_commandHistory
->addItem (ui
.le_commandInquire
->text ()+": "+commandInquireFilename
, QVariant::fromValue (data
));
2011 ui
.cb_commandHistory
->addItem (ui
.commandTextEdit
->toPlainText (), QVariant::fromValue (data
));
2014 ui
.cb_commandHistory
->setEnabled (true);
2015 saveExpandedItemList ();
2017 if (ui
.ck_commandInquire
->isChecked ())
2019 PwmdInquireData
*inq
= new PwmdInquireData ();
2021 if (!commandInquireFilename
.isEmpty ())
2023 QFile
file (commandInquireFilename
);
2025 if (!file
.open (QIODevice::ReadOnly
))
2029 switch (file
.error ())
2031 case QFile::OpenError
:
2032 rc
= GPG_ERR_ENOENT
;
2034 case QFile::PermissionsError
:
2037 case QFile::ResourceError
:
2038 rc
= GPG_ERR_ENOMEM
;
2041 rc
= GPG_ERR_UNKNOWN_ERRNO
;
2046 showError (gpg_error (rc
));
2050 inq
->setData (file
.readAll ());
2056 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdCommand
, ui
.le_commandInquire
->text ().replace ("<TAB>", "\t").toUtf8 (), Pwmd::inquireCallback
, inq
));
2060 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdCommand
, str
));
2065 PwmdMainWindow::setupToolbars ()
2071 fileToolBar
= new QToolBar (tr ("File Toolbar"), this);
2072 fileToolBar
->addAction (QIcon (":icons/rodentia-icons_folder-open-blue.svg"), tr ("Open"), this, SLOT (slotOpenFile()));
2073 fixupToolBar (fileToolBar
, FileToolBarOpen
, false, false, &w
);
2074 w
->setStatusTip (ui
.actionOpen
->statusTip ());
2075 fileToolBar
->addAction (QIcon (":icons/rodentia-icons_media-floppy.svg"), tr ("Save"), this, SLOT (slotSaveDocument()));
2076 fixupToolBar (fileToolBar
, FileToolBarSave
, false, false, &w
);
2077 w
->setStatusTip (ui
.actionSave
->statusTip ());
2078 fileToolBar
->setObjectName ("fileToolBar");
2079 addToolBar (fileToolBar
);
2081 elementToolBar
= new QToolBar (tr ("Element Toolbar"), this);
2082 elementToolBar
->setEnabled (false);
2083 elementToolBar
->addAction (QIcon (":icons/rodentia-icons_folder-add.svg"), tr ("Create Element"), this, SLOT (slotNewElement()));
2084 fixupToolBar (elementToolBar
, ElementToolBarCreate
, false, false, &w
);
2085 w
->setStatusTip (ui
.actionNewElement
->statusTip ());
2086 elementToolBar
->addAction (QIcon (":icons/rodentia-icons_user-trash-full.svg"), tr ("Delete Element"), this, SLOT (slotDeleteElement()));
2087 fixupToolBar (elementToolBar
, ElementToolBarDelete
, false, false, &w
);
2088 w
->setStatusTip (ui
.actionDeleteElement
->statusTip ());
2089 elementToolBar
->addAction (QIcon (":icons/matt-icons_font-x-generic.svg"), tr ("Rename Element"), this, SLOT (slotRenameElement()));
2090 fixupToolBar (elementToolBar
, ElementToolBarRename
, false, false, &w
);
2091 w
->setStatusTip (ui
.actionRenameElement
->statusTip ());
2093 findElementAction
= elementToolBar
->addWidget (new PwmdLineEdit
);
2094 findElementAction
->setVisible (false);
2095 PwmdLineEdit
*le
= qobject_cast
<PwmdLineEdit
*> (elementToolBar
->widgetForAction (findElementAction
));
2096 le
->setInputMethodHints (Qt::ImhNoAutoUppercase
|Qt::ImhNoPredictiveText
);
2097 le
->setClearButtonEnabled (true);
2098 le
->setPlaceholderText (tr ("Find element..."));
2099 QIcon icon
= QCommonStyle().standardIcon (QStyle::SP_ArrowUp
);
2100 a
= le
->addAction (icon
, QLineEdit::TrailingPosition
);
2101 connect (a
, SIGNAL (triggered ()), this, SLOT (slotSearchShiftEnterPressed ()));
2102 icon
= QCommonStyle().standardIcon (QStyle::SP_ArrowDown
);
2103 a
= le
->addAction (icon
, QLineEdit::TrailingPosition
);
2104 connect (a
, SIGNAL (triggered ()), this, SLOT (slotFindElement ()));
2105 connect (le
, SIGNAL (returnPressed ()), this, SLOT (slotFindElement ()));
2106 connect (le
, SIGNAL (shiftEnterPressed ()), this, SLOT (slotSearchShiftEnterPressed ()));
2107 connect (le
, SIGNAL (finished ()), this, SLOT (slotFindFinished ()));
2109 a
= elementToolBar
->addAction (QIcon (":icons/system-search.svg"), tr ("Find Element"), this, SLOT (slotFindElement ()));
2110 findElementWidget
= elementToolBar
->widgetForAction (a
);
2111 fixupToolBar (elementToolBar
, ElementToolBarFind
, false, false, &w
);
2112 w
->setStatusTip (ui
.actionFindElement
->statusTip ());
2114 QLabel
*l
= new QLabel (tr ("<a href=\"advanced\">Advanced</a>"));
2115 connect (l
, SIGNAL (linkActivated (const QString
&)), this,
2116 SLOT (slotAdvancedSearch (const QString
&)));
2117 l
->setTextInteractionFlags (Qt::LinksAccessibleByMouse
|Qt::LinksAccessibleByKeyboard
);
2118 l
->setStatusTip (tr ("Advanced element tree search..."));
2119 elementToolBar
->addWidget (l
);
2120 connect (ui
.actionAdvancedFindElement
, SIGNAL (triggered ()), this,
2121 SLOT (slotAdvancedSearchAction ()));
2122 elementToolBar
->setObjectName ("elementToolBar");
2123 addToolBar (Qt::TopToolBarArea
, elementToolBar
);
2125 contentToolBar
= new QToolBar (tr ("Content Toolbar"), this);
2126 contentToolBar
->addAction (QIcon (":icons/matt-icons_document-add.svg"), tr ("Insert Content"), this, SLOT (slotInsertContent()));
2127 fixupToolBar (contentToolBar
, ContentToolBarInsert
, false, false, &w
);
2128 w
->setStatusTip (ui
.actionInsertFile
->statusTip ());
2129 contentToolBar
->addAction (QIcon (":icons/rodentia-icons_media-floppy.svg"), tr ("Save Content"), this, SLOT (slotSaveToFile()));
2130 fixupToolBar (contentToolBar
, ContentToolBarSave
, false, false, &w
);
2131 w
->setStatusTip (ui
.actionSaveToFile
->statusTip ());
2132 contentToolBar
->addAction (QIcon (":icons/trayicon.svg"), tr ("Set Password"), this, SLOT (slotCreatePasswordAttribute()));
2133 fixupToolBar (contentToolBar
, ContentToolBarPassword
, true, false, &w
);
2134 w
->setStatusTip (ui
.actionCreatePasswordAttribute
->statusTip ());
2135 contentToolBar
->addAction (QIcon (":icons/expiry.svg"), tr ("Change expiry"), this, SLOT (slotChangeExpire()));
2136 fixupToolBar (contentToolBar
, ContentToolBarExpiry
, true, false, &w
);
2137 w
->setStatusTip (ui
.actionChangeExpire
->statusTip ());
2138 contentToolBar
->addSeparator ();
2139 contentToolBar
->addAction (QIcon (":icons/rodentia-icons_ok.svg"), tr ("Update"), this, SLOT (slotSaveContent()));
2140 fixupToolBar (contentToolBar
, ContentToolBarOk
, false, false, &w
);
2141 w
->setStatusTip (ui
.actionUpdateContent
->statusTip ());
2142 contentToolBar
->addAction (QIcon (":icons/matt-icons_view-refresh.svg"), tr ("Refresh Content"), this, SLOT (slotRefreshContent()));
2143 fixupToolBar (contentToolBar
, ContentToolBarRefresh
, false, false, &w
);
2144 w
->setStatusTip (ui
.actionRefreshContent
->statusTip ());
2145 contentToolBar
->setObjectName ("contentToolBar");
2146 addToolBar (Qt::RightToolBarArea
, contentToolBar
);
2148 passwordToolBar
= new QToolBar (tr ("Password Toolbar"), this);
2149 passwordToolBar
->addAction (QIcon (":icons/matt-icons_document-add.svg"), tr ("Insert Content"), this, SLOT (slotInsertContent()));
2150 fixupToolBar (passwordToolBar
, PasswordToolBarInsert
, false, false, &w
);
2151 w
->setStatusTip (ui
.actionInsertFile
->statusTip ());
2152 passwordToolBar
->addAction (QIcon (":icons/rodentia-icons_media-floppy.svg"), tr ("Save Content"), this, SLOT (slotSaveToFile()));
2153 fixupToolBar (passwordToolBar
, PasswordToolBarSave
, false, false, &w
);
2154 w
->setStatusTip (ui
.actionSaveToFile
->statusTip ());
2155 passwordToolBar
->addAction (QIcon (":icons/expiry.svg"), tr ("Change expiry"), this, SLOT (slotChangeExpire()));
2156 fixupToolBar (passwordToolBar
, PasswordToolBarExpiry
, false, false, &w
);
2157 w
->setStatusTip (ui
.actionChangeExpire
->statusTip ());
2158 passwordToolBar
->addSeparator ();
2159 passwordToolBar
->addAction (QIcon (":icons/rodentia-icons_ok.svg"), tr ("Update"), this, SLOT (slotSaveContent()));
2160 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false, false, &w
);
2161 w
->setStatusTip (ui
.actionUpdateContent
->statusTip ());
2162 passwordToolBar
->addAction (QIcon (":icons/matt-icons_view-refresh.svg"), tr ("Refresh Content"), this, SLOT (slotRefreshContent()));
2163 fixupToolBar (passwordToolBar
, PasswordToolBarRefresh
, false, false, &w
);
2164 w
->setStatusTip (ui
.actionRefreshContent
->statusTip ());
2165 passwordToolBar
->setObjectName ("passwordToolBar");
2166 addToolBar (Qt::RightToolBarArea
, passwordToolBar
);
2168 attributeToolBar
= new QToolBar (tr ("Attribute Toolbar"), this);
2169 attributeToolBar
->addAction (QIcon (":icons/matt-icons_document-add.svg"), tr ("New Attribute"), this, SLOT (slotNewAttribute()));
2170 fixupToolBar (attributeToolBar
, AttributeToolBarNew
, false, false, &w
);
2171 w
->setStatusTip (ui
.actionNewAttribute
->statusTip ());
2172 attributeToolBar
->addAction (QIcon (":icons/rodentia-icons_user-trash-full.svg"), tr ("Delete Attribute"), this, SLOT (slotDeleteAttribute()));
2173 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
, false, false, &w
);
2174 w
->setStatusTip (ui
.actionDeleteAttribute
->statusTip ());
2175 attributeToolBar
->addSeparator ();
2176 attributeToolBar
->addAction (QIcon (":icons/rodentia-icons_ok.svg"), tr ("Update"), this, SLOT (slotSaveContent()));
2177 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false, false, &w
);
2178 w
->setStatusTip (ui
.actionUpdateAttribute
->statusTip ());
2179 attributeToolBar
->addAction (QIcon (":icons/matt-icons_view-refresh.svg"), tr ("Refresh List"), this, SLOT (slotRefreshAttributes()));
2180 fixupToolBar (attributeToolBar
, AttributeToolBarRefresh
, false, false, &w
);
2181 w
->setStatusTip (ui
.actionRefreshAttributes
->statusTip ());
2182 attributeToolBar
->setObjectName ("attributeToolBar");
2183 addToolBar (Qt::RightToolBarArea
, attributeToolBar
);
2185 commandToolBar
= new QToolBar (tr ("Command Toolbar"), this);
2186 commandToolBar
->addAction (QIcon (":icons/rodentia-icons_media-floppy.svg"), tr ("Save Result"), this, SLOT (slotSaveCommandResult ()));
2187 fixupToolBar (commandToolBar
, CommandToolBarSave
, false, false, &w
);
2188 w
->setStatusTip (tr ("Save command result to file."));
2189 commandToolBar
->addAction (QIcon (":icons/nicubunu-Broom.svg"), tr ("Clear Results"), this, SLOT (slotClearCommand ()));
2190 fixupToolBar (commandToolBar
, CommandToolBarClear
, false, false, &w
);
2191 w
->setStatusTip (tr ("Reset command fields."));
2192 commandToolBar
->addSeparator ();
2193 commandToolBar
->addAction (QIcon (":icons/rodentia-icons_ok.svg"), tr ("Execute"), this, SLOT (slotExecuteCommand ()));
2194 fixupToolBar (commandToolBar
, CommandToolBarOk
, false, false, &w
);
2195 w
->setStatusTip (tr ("Send command to the server."));
2196 commandToolBar
->addAction (QIcon (":icons/matt-icons_view-refresh.svg"), tr ("Refresh Elements"), this, SLOT (slotRefreshElementTree ()));
2197 fixupToolBar (commandToolBar
, CommandToolBarRefresh
, false, false, &w
);
2198 w
->setStatusTip (tr ("Refresh the element tree."));
2199 commandToolBar
->setObjectName ("commandToolBar");
2200 addToolBar (Qt::RightToolBarArea
, commandToolBar
);
2201 commandToolBar
->addSeparator ();
2202 commandToolBar
->addAction (QIcon (":icons/rodentia-icons_dialog-question.svg"), tr ("Command Help"), this, SLOT (slotCommandHelp ()));
2203 fixupToolBar (commandToolBar
, CommandToolBarHelp
, false, false, &w
);
2204 w
->setStatusTip (tr ("List available commands and their syntax."));
2205 ui
.tb_commandInquireFilename
->setIcon (QIcon (":icons/matt-icons_document-add.svg"));
2209 PwmdMainWindow::confirmQuit ()
2211 QSettings
cfg ("qpwmc");
2213 if (cfg
.value ("confirmQuit", "true").toBool())
2217 msgBox
.setText (tr ("Do you really want to quit?"));
2218 msgBox
.setStandardButtons (QMessageBox::Ok
| QMessageBox::Cancel
);
2219 msgBox
.setDefaultButton (QMessageBox::Cancel
);
2220 int ret
= msgBox
.exec ();
2221 if (ret
== QMessageBox::Cancel
)
2229 PwmdMainWindow::closeEvent (QCloseEvent
*ev
)
2233 if (!doFinished (b
, true))
2235 else if (!confirmQuit ())
2239 if (clipboardTimer
->isActive ())
2241 clipboardTimer
->stop ();
2242 slotClearClipboard ();
2250 PwmdMainWindow::tabify (QPlainTextEdit
* w
)
2252 QString s
= w
->toPlainText ();
2253 int pos
= w
->textCursor ().position ();
2254 int n
= s
.count ('\t');
2259 s
.replace ("\t", "<TAB>", Qt::CaseInsensitive
);
2260 w
->document ()->setPlainText (s
);
2261 QTextCursor t
= w
->textCursor ();
2263 t
.setPosition (pos
, QTextCursor::MoveAnchor
);
2264 w
->setTextCursor (t
);
2268 PwmdMainWindow::slotGeneralOptionsDone (int n
)
2270 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventOptionsClose
));
2271 QCoreApplication::postEvent (this, ev
);
2276 ev
= new QEvent (QEvent::Type (PwmdEventReloadConfig
));
2277 QCoreApplication::postEvent (this, ev
);
2281 PwmdMainWindow::slotGeneralOptions ()
2285 optionsDialog
= new PwmdOptionsDialog (this);
2286 connect (optionsDialog
, SIGNAL (finished (int)), this, SLOT (slotGeneralOptionsDone (int)));
2289 optionsDialog
->show ();
2293 PwmdMainWindow::slotClientListDone (int)
2295 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdClientState
, "OPTION",
2296 Pwmd::inquireCallback
,
2297 new PwmdInquireData ("CLIENT-STATE=0")));
2298 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventClientListClose
));
2299 QCoreApplication::postEvent (this, ev
);
2303 PwmdMainWindow::slotClientList ()
2307 clientDialog
= new PwmdClientDialog (pwm
, invokingUser
, connectedUser
,
2309 connect (clientDialog
, SIGNAL (finished (int)), this, SLOT (slotClientListDone (int)));
2312 clientDialog
->show ();
2316 PwmdMainWindow::readConfigSettings (QString
&lastFile
, QString
&sock
, bool init
)
2318 QSettings
cfg ("qpwmc");
2320 sortElementTree
= cfg
.value ("sortElementTree", true).toBool ();
2321 cacheContent
= cfg
.value ("cacheContent", true).toBool ();
2322 cacheContentToggled ();
2323 clipboardTimeout
= cfg
.value ("clipboardTimeout", 20).toUInt();
2325 int n
= cfg
.value ("lockTimeout", 5).toInt ();
2326 if (!init
&& lockTimeout
!= n
&& pwm
&& pwm
->state () >= Pwmd::Connected
)
2329 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdLockTimeout
, "OPTION",
2330 Pwmd::inquireCallback
,
2331 new PwmdInquireData (QString ("LOCK-TIMEOUT=%1").arg (lockTimeout
* 10), pwm
->handle ())));
2335 n
= cfg
.value ("releaseTimeout", 0).toInt ();
2336 origReleaseTimeout
= releaseTimeout
= n
;
2337 if (!init
&& releaseTimeout
!= n
&& pwm
&& pwm
->state () >= Pwmd::Connected
)
2338 releaseTimer
->start(releaseTimeout
*1000);
2340 updateOnEnter
= cfg
.value ("updateOnEnter", false).toBool ();
2341 incrementalSearch
= cfg
.value ("incrementalSearch", true).toBool ();
2343 targetColor
= cfg
.value ("targetColor", "DarkOrange").value
< QColor
> ();
2344 permissionsColor
= cfg
.value ("permissionsColor", "DarkRed").value
< QColor
> ();
2345 invalidTargetColor
= cfg
.value ("invalidTargetColor", "Red").value
< QColor
> ();
2346 hilightColor
= cfg
.value ("hilightColor", "Green").value
< QColor
> ();
2347 targetLoopColor
= cfg
.value ("targetLoopColor", "DarkCyan").value
< QColor
> ();
2348 targetColorBg
= cfg
.value ("targetColorBg", "DarkGray").value
< QColor
> ();
2349 permissionsColorBg
= cfg
.value ("permissionsColorBg", "DarkGray").value
< QColor
> ();
2350 invalidTargetColorBg
= cfg
.value ("invalidTargetColorBg", "DarkGray").value
< QColor
> ();
2351 hilightColorBg
= cfg
.value ("hilightColorBg", "DarkGray").value
< QColor
> ();
2352 targetLoopColorBg
= cfg
.value ("targetLoopColorBg", "DarkGray").value
< QColor
> ();
2354 if (init
&& cfg
.value ("rememberGeometry", true).toBool ())
2356 restoreGeometry (cfg
.value ("geometry").toByteArray ());
2357 ui
.tabSplitter
->restoreState (cfg
.value ("tabGeometry").toByteArray ());
2358 ui
.attributeSplitter
->restoreState (cfg
.value ("attributeGeometry").toByteArray ());
2359 ui
.commandSplitter
->restoreState (cfg
.value ("commandGeometry").toByteArray());
2362 if (cfg
.value ("reopenLastFile").toBool())
2364 lastFile
= cfg
.value ("lastOpenedFile", "").toString ();
2365 sock
= cfg
.value ("lastSocket", "").toString ();
2369 lastFile
= QString ();
2373 bool b
= cfg
.value ("executeOnEnter").toBool ();
2374 disconnect (ui
.commandTextEdit
, SIGNAL (updateContent ()), this,
2375 SLOT (slotExecuteCommand ()));
2376 ui
.commandTextEdit
->setConfirmOnEnter (b
);
2378 connect (ui
.commandTextEdit
, SIGNAL (updateContent ()), this,
2379 SLOT (slotExecuteCommand ()));
2381 b
= cfg
.value ("updateOnEnter").toBool ();
2382 disconnect (ui
.attributeContent
, SIGNAL (updateContent ()), this,
2383 SLOT (slotSaveContent ()));
2384 /* Always enabled for attributes since the list is newline separated. But not
2385 * actually updated unless the content is. */
2386 ui
.attributeContent
->setConfirmOnEnter (true);
2387 disconnect (ui
.textEdit
, SIGNAL (updateContent ()), this,
2388 SLOT (slotSaveContent ()));
2389 ui
.textEdit
->setConfirmOnEnter (b
);
2392 connect (ui
.attributeContent
, SIGNAL (updateContent ()), this,
2393 SLOT (slotSaveContent ()));
2394 connect (ui
.textEdit
, SIGNAL (updateContent ()), this,
2395 SLOT (slotSaveContent ()));
2400 ui
.actionButtonLabels
->setChecked (cfg
.value ("buttonLabels", false).toBool ());
2401 setupToolBarLabels (ui
.actionButtonLabels
->isChecked ());
2402 restoreState (cfg
.value ("windowState").toByteArray ());
2407 PwmdMainWindow::slotSocketOptions ()
2409 PwmdSocketDialog
*w
= new PwmdSocketDialog (_socket
, this);
2410 bool needToUpdate
= needsUpdate ();
2411 bool reconn
= false;
2413 w
->setParent (this, Qt::Dialog
);
2414 int ret
= w
->exec ();
2415 QString s
= ret
? w
->socket () : QString ();
2417 /* Updates the settings database file. */
2422 PwmdRemoteHost old
, newHost
;
2423 bool a
= PwmdRemoteHost::fillRemoteHost (_socket
, old
);
2424 bool b
= PwmdRemoteHost::fillRemoteHost (s
, newHost
);
2425 bool remote
= false;
2428 old
= currentHostData
;
2430 if ((a
!= b
&& b
) || (a
&& b
&& old
!= newHost
))
2431 reconn
= remote
= true;
2432 else if (_socket
!= s
)
2437 if (!doFinished (no
, true))
2442 pwm
->setSocket (PwmdRemoteHost::socketUrl (newHost
));
2443 pwm
->setConnectParameters (newHost
.socketArgs ());
2444 _socket
= newHost
.name ();
2445 currentHostData
= newHost
;
2457 /* If the socket changed in the dialog and the document has changes then
2458 * slotCommandResult will connect to the new socket after the changes have
2459 * been committed. Otherwise, there are no document changes and we can
2461 if ((reconn
|| pwm
->state () == Pwmd::Init
) && (!needToUpdate
|| no
))
2464 reconnectSocket
= true;
2465 QTimer::singleShot (1, this, SLOT (slotConnectSocket()));
2467 else if (reconn
&& needToUpdate
)
2468 reconnectSocket
= true;
2472 PwmdMainWindow::socket ()
2478 PwmdMainWindow::filename ()
2484 PwmdMainWindow::badPassphraseCallback (void *data
, bool isFinal
)
2486 PwmdMainWindow
*d
= static_cast <PwmdMainWindow
*>(data
);
2488 gpg_error_t rc
= GPG_ERR_BAD_PASSPHRASE
;
2491 return rc
; // ignored
2493 rc
= pwmd_socket_type (d
->pwm
->handle (), &type
);
2497 /* Already handled by libpwmd. */
2498 if (type
!= PWMD_SOCKET_LOCAL
)
2499 return GPG_ERR_BAD_PASSPHRASE
;
2501 if (++d
->pinentry_try
== 3)
2502 return GPG_ERR_BAD_PASSPHRASE
;
2508 PwmdMainWindow::clearElementTree (QTreeWidget
*tree
)
2510 foreach (QTreeWidgetItem
* item
, tree
->findItems ("*",
2511 Qt::MatchRecursive
|
2514 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
2522 PwmdMainWindow::slotToggleHiddenContent (bool b
)
2524 if (doSaveContent (true))
2526 disconnect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
2527 ui
.actionHidden
->setChecked (!b
);
2528 connect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
2536 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
2538 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
2540 if (b
&& !data
->hasAttribute ("hidden"))
2541 setNewAttribute (item
, "hidden", QString (), false, true);
2542 else if (!b
&& data
->hasAttribute ("hidden"))
2543 deleteAttribute (item
, "hidden", true);
2550 PwmdMainWindow::slotSaveDocument ()
2552 doSaveContent (false, true, newFile
);
2556 PwmdMainWindow::needsUpdate ()
2558 return fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false, true)
2559 || fixupToolBar (contentToolBar
, ContentToolBarOk
, false, true)
2560 || fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false, true);
2564 PwmdMainWindow::saveDocument (bool extended
)
2566 PwmdSaveDialog
*d
= new PwmdSaveDialog (pwm
, newFile
);
2568 d
->setParent (this, Qt::Dialog
);
2579 PwmdSaveWidget
*w
= d
->widget ();
2587 PwmdMainWindow::slotSaveExtended ()
2589 doSaveContent (true, true, true);
2593 PwmdMainWindow::savePasswordContentFinalize (QTreeWidgetItem
*item
,
2594 const QString
&type
)
2596 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false);
2597 setAttribute (item
, "password", type
, true);
2598 setModifiedContent (false);
2600 if (ui
.tabWidget
->currentWidget () == ui
.contentTab
)
2601 setContentItemsEnabled ();
2605 PwmdMainWindow::updatePasswordAttribute (QTreeWidgetItem
*item
, bool queue
)
2607 QString type
= ui
.passwordWidget
->type ();
2609 PwmdInquireData
*inq
= new PwmdInquireData (QString ("SET password %1 %2").arg (elementPath (item
), type
));
2610 inq
->setUser (type
);
2611 inq
->setUserPtr (item
);
2612 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdPasswordContent
,
2614 Pwmd::inquireCallback
, inq
), queue
);
2618 PwmdMainWindow::fixupNextTabOrElement ()
2620 if (findElementAction
->isVisible ())
2622 QEvent
*ev
= new QKeyEvent (QEvent::KeyPress
, 'F', Qt::ControlModifier
);
2623 QCoreApplication::postEvent (this, ev
);
2628 ui
.elementTree
->setCurrentItem (nextElement
);
2629 else if (nextTabWidget
)
2630 ui
.tabWidget
->setCurrentWidget (nextTabWidget
);
2632 QTreeWidgetItem
*cur
= firstSelectedItem ();
2633 if ((hasTarget (oldSelectedItem
, true) || hasTarget (cur
, true))
2634 && resolveTargets (oldSelectedItem
) == resolveTargets (cur
))
2635 elementSelected (cur
, false, oldSelectedItem
);
2637 nextTabWidget
= nullptr;
2638 nextElement
= nullptr;
2640 if (editTargetAttributes
)
2642 disconnect (ui
.actionToggleTargetAttribute
, SIGNAL (triggered (bool)), this, SLOT (slotEditTargetAttributes(bool)));
2643 ui
.actionToggleTargetAttribute
->setChecked (true);
2644 connect (ui
.actionToggleTargetAttribute
, SIGNAL (triggered (bool)), this, SLOT (slotEditTargetAttributes(bool)));
2645 editAttributes (editTargetAttributes
, selectedElement
);
2648 else if (targetAttributeElement
)
2650 elementSelected (selectedElement
);
2651 targetAttributeElement
= nullptr;
2654 else if (newAttribute
)
2656 delete newAttribute
;
2657 newAttribute
= nullptr;
2658 slotNewAttribute ();
2661 else if (hiddenContent
!= -1)
2663 slotToggleHiddenContent (hiddenContent
);
2667 switch (dndOperation
)
2670 slotDndCopyElement ();
2673 slotDndMoveElement ();
2676 slotDndCreateTarget ();
2684 PwmdMainWindow::saveContentFinalize (QTreeWidgetItem
*item
,
2685 const QString
&content
, bool password
)
2688 updateContentPointer (item
, new PwmdElementContent (content
.toUtf8 ()));
2693 QTreeWidgetItem
*r
= resolveTargets (item
);
2694 if (!r
|| r
== item
)
2695 setTimeLabels (item
, true);
2697 setTimeLabels (r
, true);
2699 setModifiedContent (false);
2700 fixupToolBar (contentToolBar
, ContentToolBarOk
, false);
2701 setContent (content
, item
);
2702 fixupNextTabOrElement ();
2706 PwmdMainWindow::saveAttrContentFinalize (const QString
&path
,
2707 AttributeFinalizeT
*attr
)
2709 QString value
= attr
->content
.replace ("<TAB>", "\t", Qt::CaseInsensitive
);
2711 if (attr
->name
== "password")
2712 setContent (attr
->password
, attr
->item
);
2714 QTreeWidgetItem
*item
= !editTargetAttributes
? findElement (path
) : attr
->item
;
2715 setAttribute (item
, attr
->name
, value
, true);
2716 setModifiedContent (false);
2718 if (attr
->name
== "_target" || (attr
->name
== "_acl" && !isElementOwner (item
)))
2720 targetAttributeElement
= nullptr;
2721 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventRefreshElementTree
));
2722 QCoreApplication::postEvent (this, ev
);
2726 fixupNextTabOrElement ();
2730 PwmdMainWindow::setAttributeContentOnce (QTreeWidgetItem
*item
,
2731 const QString
&path
,
2732 const QString
&value
,
2733 bool save
, bool extended
, bool queue
)
2735 PwmdInquireData
*inq
= new PwmdInquireData (QString ("SET %1 %2 %3").arg (selectedAttribute
->text (), path
, value
));
2736 AttributeFinalizeT
*attr
= new AttributeFinalizeT
;
2738 attr
->content
= value
;
2739 attr
->name
= selectedAttribute
->text ();
2740 attr
->password
= ui
.passwordWidget
->password ();
2741 inq
->setUser (path
);
2742 inq
->setUserPtr (attr
);
2744 inq
->setSaving (extended
);
2746 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdAttrContent
, "ATTR", Pwmd::inquireCallback
, inq
);
2748 pwm
->command (cmd
, queue
2749 /* Fixes editing attribute content then selecting
2750 * another attribute before committing. */
2751 && selectedAttribute
== ui
.attributeList
->currentItem ());
2755 PwmdMainWindow::doSaveContent (bool queue
, bool save
, bool extended
,
2756 int *which
, bool force
)
2758 if (!needsUpdate ())
2762 saveDocument (extended
);
2771 QTreeWidgetItem
*item
= nullptr;
2772 QString content
= QString ();
2773 bool passwordMod
= fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false, true);
2774 bool contentMod
= ui
.passwordFrame
->isHidden() && fixupToolBar (contentToolBar
, ContentToolBarOk
, false, true);
2777 if (passwordMod
|| contentMod
)
2778 item
= selectedElement
;
2779 else if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
2780 item
= attributeElement
;
2783 contentMod
= ui
.passwordFrame
->isHidden ();
2784 passwordMod
= !contentMod
;
2785 item
= selectedElement
;
2791 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
2792 path
= elementPath (item
);
2794 if (contentMod
|| passwordMod
)
2802 b
= QByteArray (ui
.passwordWidget
->password ().toUtf8 ());
2803 updatePasswordAttribute (item
, queue
);
2806 b
= QByteArray (ui
.textEdit
->toPlainText ().toUtf8 ());
2808 if (ui
.actionBase64
->isChecked ())
2810 content
= toBase64 (item
, b
);
2813 else if (!ui
.actionBase64
->isChecked ())
2815 if (data
->attribute ("encoding") == "base64")
2817 content
= QByteArray::fromBase64 (b
);
2827 setNewAttribute (item
, "encoding", "base64", false, true);
2828 else if (base64
== 2)
2829 deleteAttribute (item
, "encoding", true);
2832 *which
= passwordMod
? Password
: Content
;
2834 path
.append (content
);
2835 PwmdInquireData
*inq
= new PwmdInquireData (path
);
2836 inq
->setHandle (pwm
->handle ());
2837 inq
->setUserBool (passwordMod
&& !queue
);
2838 inq
->setUser (content
);
2839 inq
->setUserPtr (item
);
2842 inq
->setSaving (extended
);
2844 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdStoreContent
, "STORE",
2845 Pwmd::inquireCallback
, inq
);
2847 /* Normally a STORE may be included in a BULK command but we can't do
2848 * that here because of newline characters being parsed by libassuan. */
2850 cmd
->setNeedsInquire ();
2852 pwm
->command (cmd
, queue
);
2854 else if (fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false, true))
2856 if (!selectedAttribute
2857 || !(selectedAttribute
->flags () & Qt::ItemIsEnabled
))
2859 setModifiedContent (false);
2864 *which
= Attributes
;
2866 QString value
= ui
.attributeContent
->toPlainText ().replace ("<TAB>", "\t", Qt::CaseInsensitive
);
2868 foreach (QTreeWidgetItem
*cur
, ui
.elementTree
->selectedItems ())
2870 if (selectedAttribute
->text () == "_target" || !editTargetAttributes
)
2871 path
= elementPath (cur
);
2873 setAttributeContentOnce (cur
, path
, value
, save
, extended
, queue
);
2874 if (searchAndReplace
)
2876 searchAndReplace
= false;
2886 PwmdMainWindow::slotSaveContent ()
2888 doSaveContent (true);
2893 PwmdMainWindow::slotCopyContentToClipboard ()
2895 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(selectedElement
->data (0, Qt::UserRole
));
2897 if (data
->hasAttribute ("password"))
2899 ui
.passwordWidget
->clipboardPassword ();
2903 setClipboard (ui
.textEdit
->toPlainText ().toUtf8 ());
2904 slotClipboardTimer ();
2908 PwmdMainWindow::slotSaveToFile ()
2910 PwmdFileDialog
d (this, tr ("Save to file"));
2912 d
.setAcceptMode (QFileDialog::AcceptSave
);
2913 d
.setFileMode (QFileDialog::AnyFile
);
2915 if (!d
.exec () || d
.selectedFiles ().isEmpty ())
2918 QStringList f
= d
.selectedFiles ();
2919 QFile
file (f
.at (0));
2921 if (!file
.open (QFile::WriteOnly
))
2925 m
.setText (file
.fileName ());
2926 m
.setInformativeText (file
.errorString ());
2927 m
.setIcon (QMessageBox::Warning
);
2933 PwmdTreeWidgetItemData
*idata
= qvariant_cast
<PwmdTreeWidgetItemData
*>(selectedElement
->data (0, Qt::UserRole
));
2935 if (idata
->hasAttribute ("password"))
2937 data
.append (ui
.passwordWidget
->password ().toUtf8 ());
2941 if (ui
.actionBase64
->isChecked () && idata
->attribute ("encoding") == "base64")
2942 data
= QByteArray::fromBase64 (ui
.textEdit
->toPlainText ().toUtf8 ());
2944 data
.append (ui
.textEdit
->toPlainText ().toUtf8 ());
2947 if (file
.write (data
) == -1)
2951 m
.setText (file
.fileName ());
2952 m
.setInformativeText (file
.errorString ());
2953 m
.setIcon (QMessageBox::Warning
);
2959 PwmdMainWindow::slotRefreshContent ()
2961 elementSelected (selectedElement
, true);
2965 PwmdMainWindow::cacheContentToggled ()
2970 foreach (QTreeWidgetItem
* item
, ui
.elementTree
->findItems ("*",
2976 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(item
->data (0, Qt::UserRole
));
2977 data
->setContent (nullptr);
2982 PwmdMainWindow::toBase64 (QTreeWidgetItem
*item
, QByteArray
&b
)
2985 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
2987 // Don't re-encode the content.
2988 if (data
->attribute ("encoding") == "base64")
2993 content
= b
.toBase64 ();
2995 // Do line breaks at 64 characters (OpenSSL style). It is also much
2996 // faster when setting the content for ui.textEdit.
2997 for (int c
= 0, n
= 0, t
= content
.length (); n
< t
; c
++, n
++)
3001 content
.insert (n
, "\n");
3003 t
= content
.length ();
3007 if (content
.at (content
.size ()) != '\n')
3008 content
.append ("\n");
3014 PwmdMainWindow::slotCreatePasswordAttribute ()
3016 doSaveContent (true);
3017 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
3019 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
3020 if (!data
->hasAttribute ("password")
3021 && isElementOwner (resolveTargets (item
)))
3023 setNewAttribute (item
, "password", 0, true, true);
3031 PwmdMainWindow::slotInsertContent ()
3033 bool base64
= false;
3034 PwmdFileDialog
d (this, tr ("Insert file"));
3036 d
.setFileMode (QFileDialog::ExistingFile
);
3037 d
.setOption (QFileDialog::ReadOnly
);
3039 if (!d
.exec () || !d
.selectedFiles ().count ())
3042 QFile
file (d
.selectedFiles ().at (0));
3043 if (!file
.open (QIODevice::ReadOnly
))
3047 m
.setText (file
.fileName ());
3048 m
.setInformativeText (file
.errorString ());
3049 m
.setIcon (QMessageBox::Warning
);
3054 QByteArray data
= file
.readAll ();
3056 for (int i
= 0, t
= data
.size (); i
< t
; i
++)
3058 QChar c
= data
.at (i
);
3060 if ((c
.category () == QChar::Other_Control
&& c
.toLatin1 () != '\n')
3068 PwmdTreeWidgetItemData
*idata
= qvariant_cast
< PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
3070 if (idata
->hasAttribute ("password"))
3076 m
.setText (QApplication::
3077 tr ("Binary data in file."));
3078 m
.setInformativeText (tr ("Cannot use binary data as a passphrase. Please use only plain text when setting the passphrase from a file."));
3079 m
.setIcon (QMessageBox::Critical
);
3084 ui
.passwordWidget
->setPassword (data
);
3088 QMessageBox
m (this);
3089 m
.setIcon (QMessageBox::Question
);
3090 m
.setStandardButtons (QMessageBox::Apply
|QMessageBox::Discard
|QMessageBox::Cancel
);
3091 QAbstractButton
*pb
= m
.button (QMessageBox::Apply
);
3092 pb
->setText (tr ("Append"));
3093 pb
= m
.button (QMessageBox::Discard
);
3094 pb
->setText (tr ("Overwrite"));
3095 m
.setDefaultButton (QMessageBox::Cancel
);
3096 m
.setEscapeButton (QMessageBox::Cancel
);
3097 m
.setText (tr ("Would you like to append the read file to the existing content, or overwrite existing content?"));
3100 if (r
== QMessageBox::Cancel
)
3103 QString content
= QString ();
3104 if (r
== QMessageBox::Apply
)
3105 content
= ui
.textEdit
->document ()->toPlainText ();
3109 removeAttribute (selectedElement
, "encoding");
3110 content
+= toBase64 (selectedElement
, data
);
3111 setAttribute (selectedElement
, "encoding", "base64");
3116 ui
.textEdit
->document ()->setPlainText (content
);
3117 ui
.actionBase64
->setChecked (base64
);
3119 slotToggleBase64Content (true);
3123 PwmdMainWindow::slotConnectionStateChanged (Pwmd::ConnectionState s
)
3125 Pwmd::ConnectionState old
= state
;
3128 reconnectSocket
= false;
3129 disconnectSocket
= false;
3131 /* Fixes a race condition when Pwmd::connect() fails. The handle may have
3132 * been reset (which clears the error code) before the dialog is shown.
3134 pwm
->tlsError
= pwmd_gnutls_error(pwm
->handle(), nullptr);
3139 setConnected (false);
3141 case Pwmd::Connecting
:
3142 updateConnectTimer ();
3144 case Pwmd::Connected
:
3145 updateConnectTimer (true);
3146 setConnected (true, old
);
3155 PwmdMainWindow::slotDisconnectSocket ()
3159 if (!doFinished (b
, true) && !b
)
3162 if (b
|| (!needsUpdate () && !isWindowModified ()))
3165 disconnectSocket
= true;
3169 PwmdMainWindow::slotKnownHostCallback (void *data
, const char *host
,
3170 const char *key
, size_t len
)
3172 gpg_error_t rc
= Pwmd::knownHostPrompt (data
, host
, key
, len
);
3173 emit
knownHostRc (rc
);
3177 PwmdMainWindow::updateSocketOptions ()
3179 pwmd_setopt (pwm
->handle (), PWMD_OPTION_SSH_AGENT
,
3180 currentHostData
.sshAgent ());
3181 pwmd_setopt (pwm
->handle (), PWMD_OPTION_SOCKET_TIMEOUT
,
3182 pwm
->state() == Pwmd::Init
? currentHostData
.connectTimeout ()
3183 : currentHostData
.socketTimeout ());
3184 pwmd_setopt (pwm
->handle (), PWMD_OPTION_TLS_VERIFY
,
3185 currentHostData
.tlsVerify ());
3186 if (!currentHostData
.tlsPriority ().isEmpty ())
3187 pwmd_setopt (pwm
->handle (), PWMD_OPTION_TLS_PRIORITY
,
3188 currentHostData
.tlsPriority ().toUtf8 ().data ());
3192 PwmdMainWindow::slotCancel ()
3195 androidJni
->cancel ();
3201 PwmdMainWindow::slotUpdateConnectTimer ()
3203 updateConnectTimer (false, pwm
->state () != Pwmd::Connecting
);
3207 PwmdMainWindow::updateConnectTimer (bool reset
, bool cancel
)
3209 static int remaining
= currentHostData
.connectTimeout ();
3211 if (reset
|| cancel
)
3213 if (!cancelButton
&& pwm
->state () == Pwmd::Init
&& !cancel
)
3215 cancelButton
= new QPushButton (tr ("Cancel"));
3216 connect (cancelButton
, SIGNAL (clicked ()), this,
3217 SLOT (slotCancel ()));
3218 statusBar ()->addPermanentWidget (cancelButton
);
3220 else if (cancelButton
&& pwm
->state () == Pwmd::Connected
)
3222 delete cancelButton
;
3223 cancelButton
= nullptr;
3226 remaining
= currentHostData
.connectTimeout ();
3227 progressBar
->setHidden (true);
3228 progressBar
->reset ();
3229 progressBar
->setRange (0, currentHostData
.connectTimeout ());
3230 progressBar
->setValue (0);
3234 progressBar
->setHidden (false);
3235 progressBar
->setTextVisible (true);
3236 progressBar
->setMaximum (currentHostData
.connectTimeout ());
3237 progressBar
->setFormat (QString (tr ("Connecting: timeout in %1s...")).arg (remaining
));
3238 progressBar
->setValue (remaining
--);
3239 QTimer::singleShot (1000, this, SLOT (slotUpdateConnectTimer ()));
3244 PwmdMainWindow::slotAndroidAuthenticated ()
3246 androidAuthenticating
= false;
3247 centralWidget ()->setHidden (false);
3250 /* The state gets messed up when verifying the key guard so we need to keep the
3251 * state of the previous call. */
3253 PwmdMainWindow::slotApplicationStateChanged (Qt::ApplicationState s
)
3256 QSettings
cfg ("qpwmc");
3258 if (!cfg
.value ("requireUnlock", true).toBool())
3261 if (androidAuthenticating
)
3264 if (!prev
&& (s
& Qt::ApplicationActive
))
3266 androidAuthenticating
= true;
3267 if (androidJni
->authenticate ())
3268 centralWidget ()->setHidden (true);
3270 androidAuthenticating
= false;
3277 PwmdMainWindow::slotAndroidConnectReady (PwmdRemoteHost hostData
)
3279 pwmd_setopt(pwm
->handle(), PWMD_OPTION_READ_CB_DATA
, androidJni
);
3280 pwmd_setopt(pwm
->handle(), PWMD_OPTION_WRITE_CB_DATA
, androidJni
);
3281 androidJni
->setTimeout (hostData
.connectTimeout ());
3282 androidJni
->connectSocket (hostData
);
3286 PwmdMainWindow::slotAndroidConnectResult (PwmdRemoteHost hostData
, int fd
)
3288 if (hostData
.type () != PWMD_SOCKET_SSH
)
3290 pwmd_setopt (pwm
->handle (), PWMD_OPTION_READ_CB
, PwmdAndroidJNI::read
);
3291 pwmd_setopt (pwm
->handle (), PWMD_OPTION_WRITE_CB
, PwmdAndroidJNI::write
);
3294 androidJni
->setTimeout (hostData
.socketTimeout ());
3295 pwm
->connectFd (fd
);
3299 PwmdMainWindow::slotAndroidConnectionError (gpg_error_t rc
)
3311 PwmdMainWindow::slotConnectSocket ()
3313 if (reconnectSocket
)
3316 ui
.actionDisconnect
->disconnect (this);
3317 connect (ui
.actionDisconnect
, SIGNAL (triggered()), this,
3318 SLOT (slotCancel ()));
3319 ui
.actionDisconnect
->setStatusTip (tr ("Disconnect from the pwmd server."));
3320 ui
.actionDisconnect
->setText (tr ("&Disconnect"));
3321 updateConnectTimer (true);
3323 updateSocketOptions ();
3324 pwm
->setFilename (filename ());
3327 if (currentHostData
.type () == PWMD_SOCKET_USER
)
3328 pwm
->connectHost (currentHostData
);
3337 PwmdMainWindow::openFileFinalize (gpg_error_t rc
)
3339 /* Will be deleted in Pwmd::PwmdCommandCollectorThread. */
3340 openInquireData
= nullptr;
3341 pwmd_setopt (pwm
->handle (), PWMD_OPTION_OVERRIDE_INQUIRE
, 0);
3342 pwmd_setopt (pwm
->handle (), PWMD_OPTION_LOCAL_PINENTRY
, 0);
3343 setWindowModified (false);
3347 _filename
= tr ("No file");
3348 state
= Pwmd::Connected
;
3353 releaseTimeout
= origReleaseTimeout
;
3355 releaseTimer
->start(releaseTimeout
*1000);
3357 QTimer::singleShot (1, this, SLOT (slotEditElements ()));
3361 PwmdMainWindow::slotDoOpenFile ()
3366 if (openInquireData
&& !openInquireData
->keyFile().isEmpty ())
3370 pwmd_socket_type (pwm
->handle (), &type
);
3371 pwmd_setopt (pwm
->handle (), PWMD_OPTION_OVERRIDE_INQUIRE
, 1);
3372 pwmd_setopt (pwm
->handle (), PWMD_OPTION_LOCAL_PINENTRY
, 1);
3373 pwm
->open (Pwmd::inquireCallback
, openInquireData
);
3377 if (openInquireData
)
3378 delete openInquireData
;
3380 openInquireData
= new PwmdInquireData (pwm
->handle(), pwm
->filename());
3381 pwm
->open (Pwmd::inquireCallback
, openInquireData
);
3386 PwmdMainWindow::slotOpenFileDone (int r
)
3390 _filename
= openDialog
->filename ();
3391 openInquireData
= new PwmdInquireData (pwm
->handle (),
3392 openDialog
->filename ());
3393 pwm
->setFilename (openDialog
->filename ());
3394 pwm
->setLockOnOpen (openDialog
->lock ());
3395 openInquireData
->setKeyFile (openDialog
->keyFile ());
3398 /* Depending on how the file list was scrolled (scrollbar or click-and-drag),
3399 * determines if there are a bunch of commands in the queue to fetch cache
3400 * status for each item. Since the dialog is now closed, we can remove these
3401 * queued commands entirely. */
3404 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventOpenFileClose
));
3405 QCoreApplication::postEvent (this, ev
);
3409 ev
= new QEvent (QEvent::Type (PwmdEventOpenFileConfirm
));
3410 QCoreApplication::postEvent (this, ev
);
3415 PwmdMainWindow::slotCloseFile ()
3419 if (!doFinished (b
, true))
3426 PwmdMainWindow::slotOpenFile ()
3430 if (!doFinished (b
, true))
3435 openDialog
= new PwmdOpenDialog (pwm
, this);
3436 connect (openDialog
, SIGNAL (finished (int)), this, SLOT (slotOpenFileDone (int)));
3439 openDialog
->show ();
3443 PwmdMainWindow::setWindowTitle (bool b
)
3446 pwmd_socket_type (pwm
->handle (), &type
);
3449 if (type
!= PWMD_SOCKET_LOCAL
)
3450 s
= QString ("QPwmc (%1%2)").arg (type
== PWMD_SOCKET_SSH
? currentHostData
.sshUsername ()+"@" : "", currentHostData
.hostname ());
3454 s
.append (QString (": %1[*]").arg (!b
? tr ("No file") : filename ()));
3455 QMainWindow::setWindowTitle (s
);
3459 PwmdMainWindow::setOpen (bool b
)
3461 _filename
= pwm
->filename ();
3463 selectedElement
= nullptr;
3464 attributeElement
= nullptr;
3465 dropElement
= nullptr;
3466 targetAttributeElement
= nullptr;
3467 selectedAttribute
= nullptr;
3468 ui
.elementTree
->setEnabled(b
);
3470 clearElementTree (ui
.elementTree
);
3471 clearAttributeTab ();
3472 ui
.actionReload
->setEnabled(b
);
3473 ui
.actionCut
->setEnabled (b
);
3474 ui
.actionCopy
->setEnabled (b
);
3475 ui
.actionPaste
->setEnabled (b
);
3476 fixupMenu (ui
.menuFile
, FileMenuSave
, b
);
3477 fixupMenu (ui
.menuFile
, FileMenuSaveExt
, b
);
3478 fixupMenu (ui
.menuFile
, FileMenuOpenForm
, b
);
3479 fixupMenu (ui
.menuFile
, FileMenuClose
, b
);
3480 ui
.actionFileOptions
->setEnabled (b
);
3481 elementToolBar
->setEnabled (b
);
3482 setElementItemsEnabled (nullptr, false);
3483 fixupMenu (ui
.menuView
, ViewMenuExpandAll
, b
);
3484 fixupMenu (ui
.menuView
, ViewMenuButtonLabels
, b
);
3488 PwmdMainWindow::invokingUserFinalize (const QString
&result
)
3490 invokingUser
= result
.split (",");
3494 PwmdMainWindow::currentUserFinalize (const QString
&result
)
3496 connectedUser
= result
;
3500 PwmdMainWindow::setConnected (bool b
, Pwmd::ConnectionState old
)
3505 setWindowTitle (false);
3506 pwmd_socket_type (pwm
->handle (), &type
);
3507 setWindowModified (false);
3508 setModified (false);
3510 selectedElement
= nullptr;
3511 attributeElement
= nullptr;
3512 targetAttributeElement
= nullptr;
3513 ui
.actionNew
->setEnabled(b
);
3514 ui
.actionOpen
->setEnabled(b
);
3515 fileToolBar
->setEnabled (b
);
3516 ui
.actionReload
->setEnabled(false);
3517 ui
.actionOpenForm
->setEnabled(false);
3518 ui
.tabWidget
->setEnabled(false);
3519 ui
.tabWidget
->setCurrentIndex (TabContent
);
3520 setContentItemsEnabled (true);
3521 clearAttributeTab ();
3524 fixupMenu (ui
.menuFile
, FileMenuOpen
, b
);
3528 pwmd_setopt (pwm
->handle (), PWMD_OPTION_LOCAL_PINENTRY
,
3529 type
!= PWMD_SOCKET_LOCAL
);
3530 ui
.actionDisconnect
->disconnect (this);
3531 connect (ui
.actionDisconnect
, SIGNAL (triggered()), this,
3532 SLOT (slotDisconnectSocket ()));
3533 ui
.actionDisconnect
->setStatusTip (tr ("Disconnect from the pwmd server."));
3534 ui
.actionDisconnect
->setText (tr ("&Disconnect"));
3535 if (type
!= PWMD_SOCKET_LOCAL
)
3536 pwmd_setopt (pwm
->handle (), PWMD_OPTION_SOCKET_TIMEOUT
,
3537 currentHostData
.socketTimeout ());
3539 fixupMenu (ui
.menuView
, ViewMenuClientList
, b
);
3540 ui
.tabWidget
->setEnabled (true);
3541 ui
.commandTab
->setEnabled (true);
3543 if (old
== Pwmd::Connecting
)
3545 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdInvokingUser
,
3547 Pwmd::inquireCallback
,
3548 new PwmdInquireData ("invoking_user", pwm
->handle ())),
3551 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdCurrentUser
,
3553 Pwmd::inquireCallback
,
3554 new PwmdInquireData ("user", pwm
->handle ())),
3557 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdLockTimeout
,
3559 Pwmd::inquireCallback
,
3560 new PwmdInquireData (QString ("LOCK-TIMEOUT=%1").arg (lockTimeout
*10), pwm
->handle ())),
3564 /* Prevent looping over this when the previous open failed by testing
3566 if (!filename().isEmpty () && old
== Pwmd::Connecting
)
3568 PwmdInquireData
*inq
= new PwmdInquireData (pwm
->handle(), pwm
->filename());
3570 pwm
->open (Pwmd::inquireCallback
, inq
, true);
3578 updateConnectTimer (true, true);
3579 delete cancelButton
;
3580 cancelButton
= nullptr;
3583 ui
.actionDisconnect
->disconnect (this);
3584 connect (ui
.actionDisconnect
, SIGNAL (triggered ()), this,
3585 SLOT (slotConnectSocket ()));
3586 ui
.actionDisconnect
->setStatusTip (tr ("Connect to the configured pwmd server."));
3587 ui
.actionDisconnect
->setText (tr ("&Connect"));
3589 ui
.actionDisconnect
->setEnabled (!currentHostData
.name ().isEmpty ());
3592 if (type
!= PWMD_SOCKET_LOCAL
)
3593 pwmd_setopt (pwm
->handle (), PWMD_OPTION_SOCKET_TIMEOUT
,
3594 currentHostData
.connectTimeout ());
3598 PwmdMainWindow::setElementStatusTip (QTreeWidgetItem
*item
)
3600 QStatusBar
*sb
= statusBar();
3604 sb
->showMessage (QString ());
3608 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
3612 if (data
->badTarget() && !data
->targetLoop())
3613 sb
->showMessage (tr("This element contains a target attribute that does not resolve."));
3614 else if (data
->targetLoop())
3615 sb
->showMessage (tr("This element contains a recursion loop. Use the attribute editor to edit the \"target\"."));
3616 else if (data
->badPermissions())
3617 sb
->showMessage (tr("This element has permissions that deny access to the current user ID."));
3618 else if (!isElementOwner (resolveTargets (item
)))
3619 sb
->showMessage (tr ("You cannot modify this element but may add child elements."));
3621 sb
->showMessage (QString ());
3625 PwmdMainWindow::slotElementEntered (QTreeWidgetItem
* item
, int)
3629 if (item
&& item
== previousElement
)
3632 if (previousElement
)
3634 setElementColors (previousElement
);
3635 br
= previousElement
->foreground (0);
3636 br
.setColor (previousElementColor
);
3637 previousElement
->setForeground (0, br
);
3638 br
.setColor(previousElementColorBg
);
3639 previousElement
->setBackground(0, br
);
3640 setElementColors (previousElement
);
3643 if (!item
|| dndOperation
== DndNone
)
3645 previousElement
= nullptr;
3649 br
= item
->foreground (0);
3650 previousElementColor
= br
.color ();
3651 br
.setColor (hilightColor
);
3652 item
->setForeground (0, br
);
3654 br
= item
->background (0);
3655 previousElementColorBg
= br
.color ();
3656 QBrush
bg(QPalette::Window
);
3657 bg
.setColor(hilightColorBg
);
3658 item
->setBackground(0, bg
);
3660 previousElement
= item
;
3661 setElementStatusTip (item
);
3665 PwmdMainWindow::slotElementEditorClosed (QWidget
* w
,
3666 QAbstractItemDelegate::EndEditHint h
)
3668 QLineEdit
*le
= qobject_cast
<QLineEdit
*> (w
);
3670 if (le
->text () == tr ("New element") || le
->text ().isEmpty ()
3671 || h
== QAbstractItemDelegate::RevertModelCache
)
3673 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
3674 QCoreApplication::postEvent (this, ev
);
3678 setElementItemsEnabled (selectedElement
, selectedElement
);
3682 PwmdMainWindow::event (QEvent
* ev
)
3684 int type
= ev
->type ();
3685 AttributesRetrievedEvent
*attrsEvent
;
3686 PwmdTreeWidgetItemData
*data
= nullptr;
3688 if (type
== QEvent::StatusTip
)
3690 QStatusTipEvent
*se
= static_cast < QStatusTipEvent
* >(ev
);
3691 QStatusBar
*sb
= statusBar ();
3693 sb
->showMessage (se
->tip ());
3698 if (type
>= QEvent::User
)
3699 dndOperation
= DndNone
;
3706 if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
3707 setAttributeItemsEnabled ();
3708 else if (ui
.tabWidget
->currentWidget () == ui
.contentTab
)
3709 setContentItemsEnabled ();
3710 else if (ui
.tabWidget
->currentWidget () == ui
.commandTab
)
3711 setCommandItemsEnabled ();
3713 fixupMultiToolbar ();
3716 case PwmdEventOptionsClose
:
3717 delete optionsDialog
;
3718 optionsDialog
= nullptr;
3721 case PwmdEventFileOptionsClose
:
3722 delete fileOptionsDialog
;
3723 fileOptionsDialog
= nullptr;
3724 fixupToolBar (fileToolBar
, FileToolBarOpen
, true);
3727 case PwmdEventClientListClose
:
3728 delete clientDialog
;
3729 clientDialog
= nullptr;
3732 case PwmdEventOpenFileClose
:
3734 openDialog
= nullptr;
3737 case PwmdEventOpenFileConfirm
:
3741 case PwmdEventReloadConfig
:
3744 readConfigSettings (tmp
, tmp2
, false);
3748 case PwmdEventRefreshElementTree
:
3749 case PwmdEventDnDTargetAttr
:
3750 refreshElementTree (ev
->type () == PwmdEventDnDTargetAttr
);
3754 case PwmdEventTargetAttr
:
3755 refreshElementTree ();
3758 case PwmdEventNewElementCancel
:
3760 data
= qvariant_cast
<PwmdTreeWidgetItemData
*> (newElement
->data (0, Qt::UserRole
));
3763 newElement
= nullptr;
3764 attributeElement
= selectedElement
= previousElement
;
3765 dndOperation
= DndNone
;
3766 setElementItemsEnabled (selectedElement
, selectedElement
);
3769 case PwmdEventNewAttributeCancel
:
3770 delete newAttribute
;
3771 newAttribute
= nullptr;
3772 selectedAttribute
= nullptr;
3773 slotAttributeSelected (ui
.attributeList
->item (previousAttributeIndex ()),
3777 case PwmdEventAttrsRetrieved
:
3778 attrsEvent
= static_cast<AttributesRetrievedEvent
*> (ev
);
3779 emit
attributesRetrieved (attrsEvent
->item ());
3784 return QMainWindow::event (ev
);
3788 PwmdMainWindow::newElementFinalize (QString path
)
3792 selectedElementPath
= path
;
3793 selectedElement
= nullptr;
3794 newElement
= nullptr;
3795 // Need to create an event to avoid a segfault in the mouse event
3796 // handler since this function is in an event itself.
3797 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventTargetAttr
));
3798 QCoreApplication::postEvent (this, ev
);
3802 PwmdMainWindow::renameElementFinalize ()
3805 refreshElementTree ();
3809 PwmdMainWindow::slotRenameElementUpdate (QWidget
* w
)
3811 QLineEdit
*le
= qobject_cast
<QLineEdit
*> (w
);
3815 QString path
= QString ();
3817 if (le
->text () == tr ("New element") || le
->text ().isEmpty ())
3819 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
3820 QCoreApplication::postEvent (this, ev
);
3824 for (QTreeWidgetItem
* item
= newElement
; item
; item
= item
->parent ())
3826 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(item
->data (0, Qt::UserRole
));
3828 path
.prepend (QString ("%1%2").arg (data
->hasTarget () ? "" : "",
3830 if (item
->parent ())
3831 path
.prepend ('\t');
3834 if (findElement (path
, newElement
))
3836 selectedElement
= attributeElement
= previousElement
;
3837 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewElementCancel
));
3838 QCoreApplication::postEvent (this, ev
);
3842 if (dndOperation
!= DndNone
)
3844 (void)doDndCopyElement (elementPath (copyElement
),
3845 elementPath (newElement
));
3850 PwmdInquireData
*inq
= new PwmdInquireData (path
);
3851 inq
->setUser (path
);
3852 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdNewElement
, "STORE", Pwmd::inquireCallback
, inq
));
3856 else if (!selectedElement
)
3859 int n
= selectedElementPath
.lastIndexOf ("\t") + 1;
3860 QString origName
= selectedElementPath
.mid (n
);
3862 if (le
->text ().isEmpty ())
3864 selectedElement
->setText (0, origName
);
3868 if (origName
== le
->text ())
3871 PwmdInquireData
*inq
= new PwmdInquireData (QString ("%1 %2").arg (selectedElementPath
, le
->text ()));
3872 inq
->setUser (origName
);
3873 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdRenameElement
, "RENAME",
3874 Pwmd::inquireCallback
, inq
));
3878 PwmdMainWindow::slotContentModified (bool b
)
3880 if (ui
.tabWidget
->currentWidget() == ui
.contentTab
)
3882 if (ui
.passwordFrame
->isHidden ())
3883 fixupToolBar (contentToolBar
, ContentToolBarOk
, b
);
3885 else if (ui
.tabWidget
->currentWidget() == ui
.attributeTab
)
3886 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, b
);
3888 setFileModified (b
);
3892 PwmdMainWindow::setFileModified (bool b
)
3896 ui
.textEdit
->document ()->setModified (b
);
3897 ui
.attributeContent
->document ()->setModified (b
);
3898 ui
.passwordWidget
->setModified (b
);
3901 if (b
|| (!isWindowModified () && !b
))
3906 PwmdMainWindow::setModified (bool b
)
3908 if (b
&& state
!= Pwmd::Opened
)
3911 fixupToolBar (fileToolBar
, FileToolBarSave
, b
);
3914 setWindowModified (true);
3916 if (!b
&& isWindowModified ())
3919 setFileModified (b
);
3924 PwmdMainWindow::slotExpandAll (bool b
)
3926 QTreeWidgetItem
*item
;
3927 unsigned total
= 0, n
= 0;
3929 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerItem
);
3930 progressBar
->setHidden (false);
3933 foreach (item
, ui
.elementTree
->findItems ("*",
3934 Qt::MatchRecursive
| Qt::
3935 MatchWildcard
)) total
++;
3939 progressBar
->setMaximum (total
);
3940 progressBar
->setFormat (tr ("Building view %p%"));
3943 foreach (item
, ui
.elementTree
->findItems ("*",
3944 Qt::MatchRecursive
| Qt::
3947 item
->setExpanded (b
);
3949 if (total
> 100 && !(++n
% 50))
3950 progressBar
->setValue (n
);
3953 item
= selectedElement
;
3957 item
->setExpanded (b
);
3958 item
= item
->parent ();
3962 ui
.elementTree
->scrollToItem (selectedElement
,
3963 QAbstractItemView::PositionAtCenter
);
3964 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel
);
3968 PwmdMainWindow::slotClipboardAttribute ()
3970 setClipboard (selectedAttribute
->text ());
3974 PwmdMainWindow::setClipboard (const QString
&s
)
3976 QClipboard
*c
= QApplication::clipboard ();
3978 if (c
->supportsSelection ())
3979 c
->setText (s
, QClipboard::Selection
);
3984 PwmdMainWindow::slotClipboardElementPath ()
3986 setClipboard (elementPath (selectedElement
));
3990 PwmdMainWindow::doFinished (bool &no
, bool ignore
)
3995 msgBox
.setIcon (QMessageBox::Question
);
3997 if (isWindowModified () || needsUpdate ())
3999 QMessageBox
m (QMessageBox::Question
, tr ("Save to disk?"),
4000 tr ("The current data file has changes that have yet to be written to disk. Would you like to save the changes?"));
4001 m
.addButton (QMessageBox::Yes
);
4002 m
.addButton (QMessageBox::No
);
4003 m
.addButton (QMessageBox::Cancel
);
4006 case QMessageBox::Yes
:
4007 doSaveContent (true, true, newFile
);
4009 // Prevent closing the window when there are changes since there may
4010 // be an error from somewhere like pinentry, gpg-agent, etc.
4013 case QMessageBox::Cancel
:
4014 doSaveContent (true);
4016 case QMessageBox::No
:
4017 no
= ignore
== true;
4018 return ignore
? true : false;
4028 PwmdMainWindow::slotClipboardTimer ()
4030 if (clipboardTimeout
)
4031 clipboardTimer
->start (clipboardTimeout
* 1000);
4035 PwmdMainWindow::slotClearClipboard ()
4037 QClipboard
*c
= QApplication::clipboard();
4039 clipboardTimer
->stop();
4040 if (c
->supportsSelection ())
4041 c
->clear (QClipboard::Selection
);
4043 c
->clear (QClipboard::Clipboard
);
4045 PwmdAndroidJNI::clearClipboard ();
4050 PwmdMainWindow::slotReleaseTimer ()
4052 PwmdInquireData
*inq
= new PwmdInquireData();
4053 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdUnLock
, "UNLOCK", 0, inq
);
4054 cmd
->addError (GPG_ERR_SOURCE_USER_1
, GPG_ERR_NOT_LOCKED
);
4055 if (!pwm
->command (cmd
))
4060 PwmdMainWindow::slotPasswordContentChanged ()
4062 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, true);
4063 setModifiedContent ();
4067 PwmdMainWindow::slotContentChanged ()
4069 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
4070 QPlainTextEdit
*w
= ui
.tabWidget
->currentWidget () == ui
.attributeTab
4071 ? ui
.attributeContent
: ui
.textEdit
;
4072 bool base64
= false;
4075 if (!w
->document ()->isModified ())
4077 setFileModified (false);
4081 if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
4083 if (selectedAttribute
&& selectedAttribute
->text () == "_target")
4084 tabify (ui
.attributeContent
);
4088 QString s
= w
->toPlainText ();
4090 for (int i
= 0, t
= s
.length (); i
< t
; i
++)
4094 if ((c
.category () == QChar::Other_Control
&& c
.toLatin1 () != '\n')
4103 ui
.actionBase64
->setChecked (base64
4104 || data
->attribute ("encoding") == "base64");
4105 setModifiedContent ();
4109 PwmdMainWindow::updateBusyStatusBar (Pwmd::ConnectionState s
)
4111 if (s
== Pwmd::Init
)
4112 statusBarLabel
->setText (tr ("Not connected."));
4113 else if (s
== Pwmd::Connecting
)
4114 statusBarLabel
->setText (tr ("Connecting ..."));
4116 statusBarLabel
->setText (isBusy
? tr ("Busy ...") :
4120 tr ("Ready. Use Shift-click and Ctrl-click for multi-selection."));
4125 PwmdMainWindow::slotBusy (int cmdId
, bool b
)
4128 updateBusyStatusBar (pwm
->state ());
4132 PwmdMainWindow::setBusy (bool b
, int cmdId
)
4134 static int refcount
;
4138 if (cancelButton
&& pwm
->state () == Pwmd::Connecting
)
4139 cancelButton
->setHidden (false);
4143 setElementStatusTip (selectedElement
);
4144 setCursor (Qt::BusyCursor
);
4157 if (pwm
->state () != Pwmd::Connecting
)
4160 cancelButton
->setHidden (true);
4162 progressBar
->setHidden (true);
4163 progressBar
->setValue (0);
4164 progressBar
->setMaximum (100);
4165 progressBar
->setFormat ("");
4173 case PwmdCmdIdInvalid
:
4174 case PwmdCmdIdClientList
:
4175 case PwmdCmdIdClientKill
:
4176 case PwmdCmdIdClientState
:
4177 case PwmdCmdIdClientNCache
:
4178 case PwmdCmdIdClientNClients
:
4179 case PwmdCmdIdFileGetConfig
:
4180 case PwmdCmdIdFileIsCached
:
4181 case PwmdCmdIdFileClearCache
:
4182 case PwmdCmdIdFileCacheTimeout
:
4183 case PwmdCmdIdFileKeyInfo
:
4189 if (pwm
->queued () > 0 && isBusy
)
4192 isBusy
= b
|| refcount
;
4193 if (!isBusy
&& pwm
->state () == Pwmd::Init
)
4196 fixupToolBar (fileToolBar
, FileToolBarOpen
, !isBusy
&& state
!= Pwmd::Init
4197 && !fileOptionsDialog
);
4198 fixupToolBar (fileToolBar
, FileToolBarSave
, !isBusy
&& isWindowModified ());
4199 fixupMenu (ui
.menuFile
, FileMenuSaveExt
, !isBusy
&& state
== Pwmd::Opened
);
4201 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventBusy
));
4202 QCoreApplication::postEvent (this, ev
);
4206 PwmdMainWindow::showError (gpg_error_t rc
)
4208 Pwmd::showError (rc
, pwm
, hasMultiSelection ());
4212 PwmdMainWindow::reloadFinalize ()
4214 state
= Pwmd::Connected
;
4216 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventOpenFileConfirm
));
4217 QCoreApplication::postEvent (this, ev
);
4221 PwmdMainWindow::saveExpandedItemList ()
4223 expandedItemsList
.clear ();
4224 foreach (QTreeWidgetItem
* item
,
4225 ui
.elementTree
->findItems ("*", Qt:: MatchRecursive
4226 | Qt:: MatchWildcard
))
4228 if (item
->isExpanded ())
4229 expandedItemsList
.append (elementPath (item
));
4234 PwmdMainWindow::slotReload ()
4238 if (!doFinished (b
, true))
4244 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false);
4245 fixupToolBar (contentToolBar
, ContentToolBarOk
, false);
4246 saveExpandedItemList ();
4248 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdReload
, "RESET"));
4252 PwmdMainWindow::resetSelectedItems ()
4254 QTreeWidgetItem
*item
= firstSelectedItem ();
4255 ui
.elementTree
->setCurrentItem (item
, 0, QItemSelectionModel::ClearAndSelect
);
4259 PwmdMainWindow::slotToggleMultiMode (bool b
)
4263 ui
.elementTree
->setSelectionMode (QAbstractItemView::MultiSelection
);
4265 ui
.elementTree
->setSelectionMode (QAbstractItemView::SingleSelection
);
4272 PwmdMainWindow::slotRefreshElementTree ()
4275 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false);
4276 fixupToolBar (contentToolBar
, ContentToolBarOk
, false);
4277 saveExpandedItemList ();
4278 refreshElementTree ();
4282 PwmdMainWindow::refreshElementTree (bool target
)
4284 if (state
!= Pwmd::Opened
)
4287 nextElement
= selectedElement
= attributeElement
= dropElement
= nullptr;
4288 oldSelectedItem
= nullptr;
4289 doSaveContent (true);
4291 clearAttributeTab ();
4292 PwmdInquireData
*inq
= new PwmdInquireData ("--recurse --sexp");
4293 inq
->setUserBool (target
);
4294 return pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdElementTree
,
4296 Pwmd::inquireCallback
, inq
));
4300 PwmdMainWindow::refreshElementTreeFinalize (QByteArray
&tmp
)
4302 QString path
= QString ();
4304 freeSearchResults ();
4306 if (!selectedElementPath
.isEmpty ())
4307 path
= selectedElementPath
;
4309 clearElementTree (ui
.elementTree
);
4310 previousElement
= targetAttributeElement
= nullptr;
4311 QList
< QTreeWidgetItem
* >items
= buildElementTree (tmp
);
4313 ui
.elementTree
->insertTopLevelItems (0, items
);
4314 ui
.elementTree
->setSortingEnabled (sortElementTree
);
4315 if (sortElementTree
)
4316 ui
.elementTree
->sortByColumn (0, Qt::AscendingOrder
);
4318 selectedElement
= findElement (path
);
4319 if (!selectedElement
)
4322 setCurrentElement (selectedElement
);
4324 if (ui
.actionExpandAll
->isChecked ())
4325 slotExpandAll (ui
.actionExpandAll
->isChecked ());
4326 else if (!expandedItemsList
.isEmpty ())
4328 foreach (QTreeWidgetItem
* item
,
4329 ui
.elementTree
->findItems ("*", Qt:: MatchRecursive
| Qt:: MatchWildcard
))
4331 if (expandedItemsList
.contains (elementPath (item
)))
4332 item
->setExpanded (true);
4337 QList
<QAction
*>actions
= ui
.menuElement
->actions();
4338 actions
[ElementMenuMulti
]->setChecked (false);
4340 ui
.elementTree
->scrollToItem (selectedElement
,
4341 QAbstractItemView::PositionAtCenter
);
4342 setElementStatusTip (selectedElement
);
4343 elementSelected (selectedElement
);
4347 PwmdMainWindow::slotStatusMessage (QString line
, void *)
4349 QStringList l
= QString (line
).split (" ");
4351 if (l
.at (0) == "NEWFILE")
4355 else if (l
.at (0) == "XFER")
4357 progressBar
->setHidden (false);
4358 progressBar
->setMaximum (l
.at (2).toULong (nullptr));
4359 progressBar
->setValue (l
.at (1).toULong (nullptr));
4360 progressBar
->setFormat (tr ("Transferring - %v of %m %p%"));
4362 else if (l
.at (0) == "LOCKED")
4364 progressBar
->setHidden (false);
4365 progressBar
->setMaximum (0);
4366 progressBar
->setValue (0);
4367 progressBar
->setFormat (tr ("Waiting for lock"));
4369 else if (l
.at (0) == "EXPIRE")
4371 if (l
.at(2).toUInt() != 0) // STORE status message, not GET
4372 updateElementExpiry (l
.at(2).toLong ());
4374 else if (l
.at (0) == "MODIFIED")
4376 QString title
= QString (tr ("The currently opened data file has been modified by another client."));
4377 QString desc
= QString (tr ("You will be unable to commit any current and further changes and will need to find a way to record any changes made then reopen the data file and begin editing again. This can be avoided by locking the data file before editing (File->File Options)"));
4381 m
.setInformativeText (desc
);
4382 m
.setIcon (QMessageBox::Information
);
4388 PwmdMainWindow::slotToggleBase64Content (bool)
4391 doSaveContent (true, false, false, nullptr, true);
4396 PwmdMainWindow::setCurrentElement (QTreeWidgetItem
*item
)
4398 disconnect (ui
.elementTree
,
4399 SIGNAL (currentItemChanged (QTreeWidgetItem
*, QTreeWidgetItem
*)),
4401 SLOT (slotElementSelected (QTreeWidgetItem
*, QTreeWidgetItem
*)));
4402 ui
.elementTree
->setCurrentItem (item
, 0, QItemSelectionModel::ClearAndSelect
);
4403 connect (ui
.elementTree
,
4404 SIGNAL (currentItemChanged (QTreeWidgetItem
*, QTreeWidgetItem
*)),
4406 SLOT (slotElementSelected (QTreeWidgetItem
*, QTreeWidgetItem
*)));
4410 PwmdMainWindow::updateContentPointer (QTreeWidgetItem
* i
,
4411 PwmdElementContent
* newData
)
4413 QTreeWidgetItem
*r
= resolveTargets (i
);
4419 PwmdTreeWidgetItemData
*data
=
4420 qvariant_cast
< PwmdTreeWidgetItemData
* >(r
->data (0, Qt::UserRole
));
4421 PwmdElementContent
*old
= data
->content ();
4423 // For elements with a "_target" attribute pointing to this element.
4424 foreach (QTreeWidgetItem
* item
, ui
.elementTree
->findItems ("*",
4433 data
= qvariant_cast
<PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
4434 if ((old
&& data
->content () == old
) || (resolveTargets (item
) == r
))
4435 data
->setContent (newData
);
4438 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(r
->data (0, Qt::UserRole
));
4439 data
->setContent (newData
);
4443 PwmdMainWindow::createAttributeCache (QTreeWidgetItem
*item
, const QString
&tmp
)
4445 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
4447 if (tmp
.isEmpty () || !data
)
4450 QStringList attrs
= tmp
.split ("\n");
4451 PwmdAttributeList
*newAttrs
= new PwmdAttributeList ();
4453 for (int attr
= 0, t
= attrs
.count (); attr
< t
; attr
++)
4455 int n
= attrs
.at (attr
).indexOf (QChar (' '));
4459 s
.append (attrs
.at (attr
));
4461 s
.append (attrs
.at (attr
).left (n
));
4463 data
->addAttribute (newAttrs
, s
, attrs
.at (attr
).mid (n
+ 1));
4466 data
->setAttributes (newAttrs
);
4467 data
->setNeedsAttrRefresh (false);
4472 PwmdMainWindow::previousAttributeIndex ()
4474 if (advancedSearchDialog
&& advancedSearchDialog
->isVisible ())
4476 if (currentSearchResult
4477 && ((currentSearchResult
->resultType () & SearchResult::Attr
)
4478 || (currentSearchResult
->resultType () & SearchResult::AttrValue
)))
4479 return currentSearchResult
->curAttr ();
4482 for (int i
= 0; i
< ui
.attributeList
->count (); i
++)
4484 QListWidgetItem
*item
= ui
.attributeList
->item (i
);
4486 if (item
->text () == previousAttributeText
)
4494 PwmdMainWindow::elementSelectedFinalize (QTreeWidgetItem
*item
,
4495 const QString
&result
, bool attrs
)
4497 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
4499 previousElement
= selectedElement
;
4500 selectedElement
= attributeElement
= item
;
4501 ui
.elementTree
->scrollToItem (selectedElement
);
4502 setElementColors (item
);
4503 setElementItemsEnabled (item
, true);
4505 if (sortElementTree
)
4506 item
->sortChildren (0, Qt::AscendingOrder
);
4508 if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
4509 refreshAttributeListFinalize (item
, QString (), false);
4511 if (ui
.tabWidget
->currentWidget () == ui
.contentTab
)
4513 if (data
->hasAttribute ("password"))
4514 setPasswordItemsEnabled ();
4516 setContentItemsEnabled ();
4518 else if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
4523 slotEditAttributes ();
4526 setContent (result
, item
);
4527 ui
.tabWidget
->setEnabled (true);
4529 updateContentPointer (item
, new PwmdElementContent (result
.toUtf8 ()));
4531 if (item
->isDisabled ())
4532 ui
.contentTab
->setEnabled (false);
4536 PwmdMainWindow::elementSelected (QTreeWidgetItem
* item
, bool refresh
,
4537 QTreeWidgetItem
*old
)
4545 bool attrs
= refreshAttributeList (item
, !cacheContent
|| refresh
, true);
4546 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
4547 QString s
= QString ();
4549 if (cacheContent
&& data
->contentCached () && !refresh
)
4551 s
= QString::fromUtf8 (data
->content ()->data(), -1);
4552 elementSelectedFinalize (item
, s
, attrs
);
4554 else if (!data
->hasError () && (refresh
|| item
!= old
))
4556 if (hasMultiSelection ())
4559 PwmdInquireData
*inq
= new PwmdInquireData (elementPath (item
));
4560 inq
->setUserPtr (item
);
4561 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdGetContent
, "GET",
4562 Pwmd::inquireCallback
, inq
));
4568 if (ui
.tabWidget
->currentWidget () == ui
.contentTab
)
4570 ui
.contentTab
->setEnabled (false);
4571 setContentItemsEnabled (true);
4572 ui
.attributeTab
->setEnabled (false);
4574 else if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
4576 if (targetAttributeElement
)
4578 setElementColors (targetAttributeElement
, true, true);
4579 targetAttributeElement
= nullptr;
4580 selectedElement
= attributeElement
= item
;
4583 slotEditAttributes ();
4591 PwmdMainWindow::hasOwnerOfItemSelected ()
4593 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
4595 if (isElementOwner (item
))
4603 PwmdMainWindow::setAttributeItemsEnabled (bool b
, QTreeWidgetItem
*multi
)
4605 QTreeWidgetItem
*element
= multi
? multi
: selectedElement
;
4606 element
= !multi
&& attributeElement
? attributeElement
: element
;
4611 setContentItemsEnabled (false);
4612 setCommandItemsEnabled (false);
4613 setPasswordItemsEnabled (false);
4614 ui
.tabWidget
->setCurrentWidget (ui
.attributeTab
);
4617 setElementItemsEnabled (element
, !isBusy
, multi
);
4620 attributeToolBar
->setHidden (!b
);
4622 b
= b
&& element
&& state
== Pwmd::Opened
&& !isBusy
;
4623 attributeToolBar
->setEnabled (b
);
4624 ui
.attributeTab
->setEnabled (b
);
4625 PwmdTreeWidgetItemData
*data
= nullptr;
4627 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(element
->data (0, Qt::UserRole
));
4629 b
= b
&& data
&& !data
->hasError ()
4630 && isElementOwner (resolveTargets (element
));
4632 fixupMenu (ui
.menuAttributes
, AttributeMenuTarget
, !isBusy
&& !multi
4633 && (targetAttributeElement
4634 || (hasTarget (element
) && !badTarget (element
)))
4635 && ui
.tabWidget
->currentWidget () == ui
.attributeTab
);
4636 fixupToolBar (attributeToolBar
, AttributeToolBarNew
, b
);
4637 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
,
4638 b
&& ui
.attributeList
->count () > 1
4639 && ui
.attributeList
->selectedItems ().count ());
4640 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, !isBusy
&& data
4641 && !data
->badPermissions ()
4642 && fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false, true));
4643 fixupToolBar (attributeToolBar
, AttributeToolBarRefresh
, !isBusy
&& !multi
4645 && ui
.tabWidget
->currentWidget () == ui
.attributeTab
4646 && hasSingleSelection ());
4647 ui
.cb_searchAndReplace
->setEnabled (ui
.attributeList
->currentItem ());
4651 PwmdMainWindow::setContentItemsEnabled (bool b
, bool hide
,
4652 QTreeWidgetItem
*multi
)
4654 QTreeWidgetItem
*element
= multi
? multi
: selectedElement
;
4655 PwmdTreeWidgetItemData
*data
= nullptr;
4657 if (!multi
&& ui
.tabWidget
->currentWidget () == ui
.contentTab
)
4658 setElementColors (selectedElement
);
4661 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(element
->data (0, Qt::UserRole
));
4665 setAttributeItemsEnabled (false);
4666 setCommandItemsEnabled (false);
4667 if (!data
|| !data
->hasAttribute ("password"))
4668 setPasswordItemsEnabled (false);
4669 ui
.tabWidget
->setCurrentWidget (ui
.contentTab
);
4672 setElementItemsEnabled (element
, b
&& !isBusy
, multi
);
4674 if ((multi
|| element
) && b
)
4676 if (data
&& data
->hasAttribute ("password"))
4678 setPasswordItemsEnabled (true, multi
);
4686 contentToolBar
->setHidden (!b
&&
4687 (hide
|| ui
.tabWidget
->currentWidget () != ui
.contentTab
));
4689 ui
.textEdit
->setHidden (data
&& data
->hasAttribute ("hidden"));
4690 ui
.passwordWidget
->setHidden (true);
4693 ui
.textEdit
->setEnabled (element
&& hasSingleSelection ());
4694 contentToolBar
->setEnabled (element
&&
4695 data
&& !data
->hasError () && !isBusy
);
4697 && element
&& state
== Pwmd::Opened
4698 && !element
->isDisabled ()
4699 && !badTarget (element
)
4700 && data
&& !data
->badPermissions ()
4701 && isElementOwner (resolveTargets (element
));
4705 if (data
&& !ui
.f_expire
->isHidden ())
4706 setElementExpireLabel (data
->attribute ("_expire").toUInt ());
4708 ui
.f_expire
->setHidden (!b
|| (data
&& data
->attribute ("_expire").isEmpty ()));
4709 ui
.f_expire
->setEnabled (b
&& isElementOwner (element
));
4710 ui
.contentTab
->setEnabled (b
&& !isBusy
);
4713 fixupMenu (ui
.menuContent
, ContentMenuBase64
, b
&& !isBusy
4714 && hasSingleSelection ());
4715 fixupMenu (ui
.menuContent
, ContentMenuHidden
, b
&& !isBusy
4716 && hasSingleSelection ());
4717 fixupMenu (ui
.menuContent
, ContentMenuClipboard
, data
&& !data
->hasError ()
4718 && hasSingleSelection ()
4719 && isElementOwner (element
, true));
4720 fixupToolBar (contentToolBar
, ContentToolBarSave
, data
&& !data
->hasError ()
4721 && hasSingleSelection ()
4722 && isElementOwner (element
, true));
4723 fixupToolBar (contentToolBar
, ContentToolBarInsert
, b
&& !isBusy
4724 && hasSingleSelection ());
4725 fixupToolBar (contentToolBar
, ContentToolBarRefresh
, b
&& !isBusy
4726 && hasSingleSelection ());
4727 fixupToolBar (contentToolBar
, ContentToolBarPassword
, b
&& !isBusy
4728 && isElementOwner (resolveTargets (element
)));
4729 fixupToolBar (contentToolBar
, ContentToolBarExpiry
, b
&& !isBusy
4730 && isElementOwner (resolveTargets (element
)));
4733 setElementStatusTip (selectedElement
);
4737 PwmdMainWindow::setElementExpireLabel (long expire
)
4741 date
.setSecsSinceEpoch (expire
);
4742 ui
.l_expires
->setText (date
.toString ());
4743 ui
.l_expiresTitle
->setText (tr (expire
<= time (nullptr) ? "Expired:" : "Expires:"));
4747 PwmdMainWindow::setPasswordItemsEnabled (bool b
, QTreeWidgetItem
*multi
)
4749 QTreeWidgetItem
*element
= multi
? multi
: selectedElement
;
4753 setContentItemsEnabled (false);
4754 setAttributeItemsEnabled (false);
4755 setCommandItemsEnabled (false);
4756 ui
.contentTab
->setEnabled (true);
4759 PwmdTreeWidgetItemData
*data
= nullptr;
4761 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(element
->data (0, Qt::UserRole
));
4765 ui
.passwordFrame
->setHidden (!b
);
4766 ui
.passwordFrame
->setEnabled (element
&&
4767 isElementOwner (element
, true)
4768 && hasSingleSelection ());
4769 ui
.textEdit
->setHidden (true);
4770 ui
.passwordWidget
->setHidden (false);
4771 passwordToolBar
->setHidden (!b
);
4772 passwordToolBar
->setEnabled (element
);
4775 b
= (multi
|| b
) && element
&& state
== Pwmd::Opened
4776 && !element
->isDisabled () && !badTarget (element
);
4780 ui
.f_expire
->setHidden (!b
|| (data
&& data
->attribute ("_expire").isEmpty ()));
4781 if (data
&& !ui
.f_expire
->isHidden ())
4782 setElementExpireLabel (data
->attribute ("_expire").toUInt ());
4785 b
= b
&& isElementOwner (resolveTargets (element
));
4787 ui
.f_expire
->setEnabled (b
);
4789 fixupToolBar (passwordToolBar
, PasswordToolBarInsert
, b
&& !isBusy
4790 && hasSingleSelection ());
4791 fixupToolBar (passwordToolBar
, PasswordToolBarSave
, b
&& !isBusy
4792 && hasSingleSelection ());
4793 fixupToolBar (passwordToolBar
, PasswordToolBarExpiry
, b
&& !isBusy
);
4794 fixupToolBar (passwordToolBar
, PasswordToolBarRefresh
, b
&& !isBusy
4795 && hasSingleSelection ());
4797 fixupMenu (ui
.menuContent
, ContentMenuInsert
, b
&& !isBusy
4798 && hasSingleSelection ());
4799 fixupMenu (ui
.menuContent
, ContentMenuSave
, data
&& !data
->hasError ()
4800 && hasSingleSelection ());
4801 fixupMenu (ui
.menuContent
, ContentMenuClipboard
, data
&& !data
->hasError ()
4802 && hasSingleSelection ());
4803 fixupMenu (ui
.menuContent
, ContentMenuExpiry
, b
&& !isBusy
);
4804 fixupMenu (ui
.menuContent
, ContentMenuPassword
, false);
4805 fixupMenu (ui
.menuContent
, ContentMenuBase64
, false);
4806 fixupMenu (ui
.menuContent
, ContentMenuHidden
, false);
4807 fixupMenu (ui
.menuContent
, ContentMenuRefresh
, b
&& !isBusy
4808 && hasSingleSelection ());
4809 passwordToolBar
->setEnabled (b
&& !isBusy
);
4810 ui
.passwordWidget
->setEditable (b
&& !isBusy
4811 && hasSingleSelection ()
4812 && isElementOwner (resolveTargets (element
)));
4817 PwmdMainWindow::setCommandItemsEnabled (bool b
, QTreeWidgetItem
*multi
)
4821 ui
.tabWidget
->setEnabled (true);
4822 setContentItemsEnabled (false);
4823 setAttributeItemsEnabled (false);
4824 setPasswordItemsEnabled (false);
4827 setElementItemsEnabled (selectedElement
, multi
|| !isBusy
, multi
);
4828 ui
.commandTab
->setEnabled (b
&& !isBusy
);
4829 commandToolBar
->setHidden (!b
);
4830 fixupToolBar (commandToolBar
, CommandToolBarOk
, state
== Pwmd::Opened
4831 && !isBusy
&& !ui
.commandTextEdit
->toPlainText ().isEmpty ());
4832 fixupToolBar (commandToolBar
, CommandToolBarRefresh
, state
== Pwmd::Opened
4834 fixupToolBar (commandToolBar
, CommandToolBarHelp
, !isBusy
4835 && (state
== Pwmd::Opened
|| state
== Pwmd::Connected
));
4839 PwmdMainWindow::setElementItemsEnabled (QTreeWidgetItem
*item
, bool b
,
4840 QTreeWidgetItem
*multi
)
4842 QTreeWidgetItem
*element
= multi
? multi
: item
;
4843 PwmdTreeWidgetItemData
*data
= nullptr;
4848 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(element
->data (0, Qt::UserRole
));
4851 elementToolBar
->setEnabled (state
== Pwmd::Opened
&& !isBusy
);
4852 fixupToolBar (elementToolBar
, ElementToolBarCreate
, !newElement
4853 && state
== Pwmd::Opened
4854 && !hasMultiSelection ());
4855 fixupToolBar (elementToolBar
, ElementToolBarDelete
, b
&&
4856 ((data
&& !data
->badPermissions() && isElementOwner (element
))
4857 || isElementOwner (element
)));
4858 fixupToolBar (elementToolBar
, ElementToolBarRename
, b
&&
4859 data
&& !data
->badPermissions() && isElementOwner (element
)
4860 && hasSingleSelection ());
4861 fixupToolBar (elementToolBar
, ElementToolBarFind
, state
== Pwmd::Opened
4862 && !isBusy
&&ui
.elementTree
->topLevelItemCount () > 1);
4864 contentToolBar
->setEnabled (element
&& b
);
4867 QList
<QAction
*>actions
= ui
.menuElement
->actions();
4868 actions
[ElementMenuNewRoot
]->setEnabled (state
== Pwmd::Opened
);
4869 actions
[ElementMenuNew
]->setEnabled (state
== Pwmd::Opened
&& element
4870 && !data
->badPermissions()
4871 && !data
->badTarget () && b
4872 && hasSingleSelection ());
4873 actions
[ElementMenuNewSibling
]->setEnabled (state
== Pwmd::Opened
&& element
4874 && element
->parent ()
4875 && hasSingleSelection ());
4876 actions
[ElementMenuResolveTargets
]->setEnabled (element
4877 && hasTarget (element
, true)
4878 && !badTarget (element
)
4879 && (!data
->badPermissions() ||
4880 resolveTargets (element
))
4882 && hasSingleSelection ());
4883 actions
[ElementMenuEditContent
]->setEnabled (element
&& b
&&
4884 ((!data
->badPermissions()
4885 && ui
.tabWidget
->currentWidget() != ui
.contentTab
)
4887 (ui
.tabWidget
->currentWidget() != ui
.attributeTab
)));
4888 actions
[ElementMenuRefreshTree
]->setEnabled (state
== Pwmd::Opened
4891 actions
[ElementMenuMulti
]->setEnabled (state
== Pwmd::Opened
4893 && ui
.elementTree
->findItems ("*", Qt::MatchRecursive
|Qt::MatchWildcard
).count () > 1);
4895 actions
[ElementMenuMulti
]->setVisible (false);
4900 PwmdMainWindow::slotElementClicked (QTreeWidgetItem
*, int)
4902 slotFindFinished ();
4906 PwmdMainWindow::fixupMultiToolbar ()
4910 int count
= ui
.elementTree
->selectedItems ().count ();
4915 if (ui
.tabWidget
->currentWidget () == ui
.contentTab
)
4917 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
4919 setContentItemsEnabled (true, false, item
);
4920 b
= fixupToolBar (contentToolBar
, ContentToolBarPassword
, false,
4923 mask
|= ContentPasswordMask
;
4925 b
= fixupToolBar (contentToolBar
, ContentToolBarExpiry
, false,
4928 mask
|= ContentExpiryMask
;
4931 fixupToolBar (contentToolBar
, ContentToolBarPassword
,
4932 (mask
& ContentPasswordMask
));
4933 fixupToolBar (contentToolBar
, ContentToolBarExpiry
,
4934 (mask
& ContentExpiryMask
));
4936 contentToolBar
->setEnabled (true);
4938 else if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
4940 b
= fixupToolBar (attributeToolBar
, AttributeToolBarRefresh
, false, true);
4941 fixupToolBar (attributeToolBar
, AttributeToolBarRefresh
, b
&& count
== 1);
4943 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
4945 setContentItemsEnabled (true, false, item
);
4946 setAttributeItemsEnabled (true, item
);
4947 b
= fixupToolBar (attributeToolBar
, AttributeToolBarNew
, false,
4950 mask
|= AttributeNewMask
;
4952 b
= fixupToolBar (attributeToolBar
, AttributeToolBarDelete
, false,
4955 mask
|= AttributeDeleteMask
;
4958 fixupToolBar (attributeToolBar
, AttributeToolBarNew
,
4959 (mask
& AttributeNewMask
));
4960 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
,
4961 (mask
& AttributeDeleteMask
));
4963 attributeToolBar
->setEnabled (true);
4965 else if (ui
.tabWidget
->currentWidget () == ui
.commandTab
)
4967 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
4968 setCommandItemsEnabled (true, item
);
4972 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
4974 setElementItemsEnabled (nullptr, true, item
);
4975 b
= fixupToolBar (elementToolBar
, ElementToolBarDelete
, false, true);
4978 fixupToolBar (elementToolBar
, ElementToolBarDelete
, mask
!= 0);
4981 /* Test if the command queue contains a command that when completed will
4982 * refresh the element tree. */
4984 PwmdMainWindow::hasQueuedRefreshTree ()
4986 if (pwm
->isQueued (PwmdCmdIdElementTree
)
4987 || pwm
->isQueued (PwmdCmdIdDeleteElement
)
4988 || pwm
->isQueued (PwmdCmdIdRenameElement
)
4989 || pwm
->isQueued (PwmdCmdIdNewElement
)
4990 || pwm
->isQueued (PwmdCmdIdDndMoveElement
)
4991 || pwm
->isQueued (PwmdCmdIdDndCopyElement
)
4992 || pwm
->isQueued (PwmdCmdIdDndCreateTarget
))
4998 /* This slot is called after slotElementSelected(). It seems to be consistant
4999 * in the firing order but may break in the future in which case element
5000 * selection will also break. */
5002 PwmdMainWindow::slotItemSelectionChanged ()
5004 QList
<QTreeWidgetItem
*> items
= ui
.elementTree
->selectedItems ();
5005 static unsigned lastCount
;
5006 QTreeWidgetItem
*item
= firstSelectedItem ();
5008 fixupMultiToolbar ();
5010 /* Prevent fetching content for other selected items. */
5011 if (items
.count () > 1)
5013 lastCount
= items
.count ();
5017 /* The nextElement is set when there are commands queued from
5018 * slotElementSelected() and is the item to be selected when the queue
5019 * becomes empty. The lastCount is the number of selected items during the
5020 * previous call to this function. Here, it means that the selection has
5021 * changed back to only one item and the command queue is to be run. It
5022 * handles the case that the content of an element has been edited but yet to
5023 * be committed while selecting other elements. */
5024 if (nextElement
&& lastCount
> 1)
5026 lastCount
= items
.count ();
5027 nextElement
= nullptr;
5029 /* A different element selected with content of the original element yet to
5031 else if (nextElement
)
5033 lastCount
= items
.count ();
5034 elementSelected (oldSelectedItem
, false, oldSelectedItem
);
5037 lastCount
= items
.count ();
5039 /* Handle the case where an item is selected, then edited, then other items
5040 * are selected and the edited item deselected. Let the edit be queued for
5042 if (!items
.contains (oldSelectedItem
))
5044 oldSelectedItem
= nullptr;
5048 if (!hasQueuedRefreshTree ())
5049 elementSelected (item
, false, oldSelectedItem
);
5055 PwmdMainWindow::slotElementSelected (QTreeWidgetItem
* item
,
5056 QTreeWidgetItem
* old
)
5058 /* If there is content yet to be commited, only test for it once rather than
5059 * messing up a multi-element selection. */
5060 if (!pwm
->isQueued (PwmdCmdIdStoreContent
)
5061 && !pwm
->isQueued (PwmdCmdIdAttrContent
)
5062 && doSaveContent (true))
5064 selectedElement
= previousElement
= old
;
5068 if (!hasMultiSelection ())
5069 oldSelectedItem
= old
;
5073 PwmdMainWindow::setAttributeContent (const QString
& str
)
5075 disconnect (ui
.attributeContent
, SIGNAL (modificationChanged (bool)), this,
5076 SLOT (slotContentModified (bool)));
5077 disconnect (ui
.attributeContent
, SIGNAL (textChanged ()), this, SLOT (slotContentChanged ()));
5078 ui
.attributeContent
->document ()->setPlainText (str
);
5079 connect (ui
.attributeContent
, SIGNAL (textChanged ()), SLOT (slotContentChanged ()));
5080 connect (ui
.attributeContent
, SIGNAL (modificationChanged (bool)), this,
5081 SLOT (slotContentModified (bool)));
5082 ui
.attributeContent
->document ()->setModified (false);
5084 if (attributeElement
)
5086 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(attributeElement
->data (0, Qt::UserRole
));
5087 ui
.attributeContent
->setReadOnly (data
->badPermissions ());
5092 PwmdMainWindow::setContent (const QString
& str
, QTreeWidgetItem
*item
)
5094 PwmdTreeWidgetItemData
*data
= nullptr;
5096 item
= item
? item
: selectedElement
;
5099 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5101 ui
.hiddenContentFrame
->setHidden (true);
5105 bool base64
= data
->attribute ("encoding") == "base64";
5107 ui
.actionBase64
->setChecked (base64
);
5109 if (item
== selectedElement
)
5111 ui
.actionHidden
->setChecked (data
->hasAttribute ("hidden"));
5112 if (!data
->hasAttribute ("password"))
5113 ui
.hiddenContentFrame
->setHidden (!ui
.actionHidden
->isChecked ());
5115 if (ui
.actionHidden
->isChecked ())
5116 ui
.hiddenContentLabel
->setText (QString ("<html><head/><body><p><span style=\" font-style:italic;\">%1 %2.</span></p></body></html>").arg (tr ("The content for this element is hidden. Uncheck the Hidden item in the Content menu to make it visible. The length of the hidden content is "), QString::number (str
.length ())));
5120 disconnect (ui
.passwordWidget
, SIGNAL (modified ()), this,
5121 SLOT (slotPasswordContentChanged ()));
5122 disconnect (ui
.textEdit
, SIGNAL (modificationChanged (bool)), this,
5123 SLOT (slotContentModified (bool)));
5124 disconnect (ui
.textEdit
, SIGNAL (textChanged ()), this,
5125 SLOT (slotContentChanged ()));
5126 if (item
== selectedElement
)
5128 if (data
&& data
->hasAttribute ("password"))
5130 ui
.passwordWidget
->setPassword (str
, !isElementOwner (item
));
5131 ui
.passwordWidget
->setType (data
->attribute ("password"));
5132 ui
.hiddenContentFrame
->setHidden (true);
5133 fixupToolBar (passwordToolBar
, PasswordToolBarOk
, false);
5134 ui
.textEdit
->document ()->setPlainText ("");
5138 ui
.passwordWidget
->setPassword ("");
5139 ui
.textEdit
->document ()->setPlainText (str
);
5140 ui
.textEdit
->document ()->setModified (false);
5143 ui
.contentTab
->setEnabled (!data
->hasError ());
5147 connect (ui
.passwordWidget
, SIGNAL (modified ()), this,
5148 SLOT (slotPasswordContentChanged ()));
5149 connect (ui
.textEdit
, SIGNAL (textChanged ()), this,
5150 SLOT (slotContentChanged ()));
5151 connect (ui
.textEdit
, SIGNAL (modificationChanged (bool)), this,
5152 SLOT (slotContentModified (bool)));
5156 hasFlag (const QString
&str
, const QString
&flags
)
5158 if (flags
.isEmpty () || str
.isEmpty ())
5161 for (int i
= 0; i
< flags
.length (); i
++)
5163 if (str
.contains (flags
.at (i
)))
5171 PwmdMainWindow::hasBadTarget (QTreeWidgetItem
* item
, const QString
& path
,
5172 const QString
& flags
)
5175 bool notAllowed
= hasFlag (flags
, "P");
5176 PwmdTreeWidgetItemData
*data
=
5177 qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5181 Qt::ItemFlags flags
= item
->flags ();
5183 flags
&= ~Qt::ItemIsEditable
;
5184 item
->setFlags (flags
);
5185 data
->setBadPermissions ();
5188 if (!data
->hasTarget ())
5190 setElementColors (item
);
5194 if (hasFlag (flags
, "EO"))
5197 data
->setBadTarget (b
);
5200 data
->setTarget (path
);
5201 bool loop
= hasFlag (flags
, "O");
5202 data
->setTargetLoop (loop
);
5203 setElementColors (item
);
5205 if (data
->badPermissions())
5212 PwmdMainWindow::hasTarget (const QTreeWidgetItem
* item
, bool parent
)
5217 PwmdTreeWidgetItemData
*data
=
5218 qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5220 if (!parent
|| data
->hasTarget ())
5221 return data
->hasTarget ();
5223 item
= item
->parent ();
5226 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5227 if (data
->hasTarget ())
5229 item
= item
->parent ();
5236 PwmdMainWindow::targetLoop (const QTreeWidgetItem
* item
)
5238 PwmdTreeWidgetItemData
*data
=
5239 qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5241 return data
->targetLoop ();
5245 PwmdMainWindow::badTarget (const QTreeWidgetItem
* item
)
5247 PwmdTreeWidgetItemData
*data
=
5248 qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
5250 return data
? data
->badTarget () : false;
5254 PwmdMainWindow::elementName (const QTreeWidgetItem
* item
)
5259 return item
->text (0);
5263 PwmdMainWindow::setItemText (QTreeWidgetItem
* item
, const QString
& str
,
5266 item
->setText (0, str
);
5267 PwmdTreeWidgetItemData
*data
= new PwmdTreeWidgetItemData (target
, str
);
5268 item
->setData (0, Qt::UserRole
, QVariant::fromValue (data
));
5272 QBrush br
= item
->foreground (0);
5274 br
.setColor (targetColor
);
5275 item
->setForeground (0, br
);
5278 item
->setFlags (item
->flags () | Qt::ItemIsEditable
);
5284 ElementPath (QString path
, QString flags
= 0)
5289 ~ElementPath () { };
5290 QString
path () { return _path
; };
5291 QString
flags () { return _flags
; };
5296 ElementAttr (QString name
, QString value
= 0)
5301 ~ElementAttr () { };
5302 QString
name () { return _name
; };
5303 QString
value () { return _value
; };
5310 QList
<ElementAttr
*> attrs () { return _attrs
; };
5311 void setAttrs (QList
<ElementAttr
*>list
) { _attrs
= list
; };
5315 QList
<ElementAttr
*> _attrs
;
5318 #define EXTRACT_TOKEN(ba,offset,ns,n,var) \
5321 foreach (QChar c, ba) \
5324 ns += QString::number (c.digitValue ()); \
5329 n = ns.toUInt (nullptr); \
5330 var = ba.mid (++offset, n); \
5331 ba = ba.mid (offset+n);
5333 QList
<QTreeWidgetItem
*>PwmdMainWindow::buildElementTree (QByteArray
&sexp
,
5336 QList
<QTreeWidgetItem
*>elementTree
;
5337 QList
<ElementPath
*>elementPaths
;
5340 n
= sexp
.indexOf ("(4:path");
5341 if (sexp
.isEmpty () || !sexp
.startsWith ("(11:list-result(") || n
!= 15)
5344 sexp
= sexp
.mid (n
);
5345 while (sexp
.startsWith ("(4:path"))
5347 QString ns
, path
, flags
;
5348 unsigned offset
= 0;
5350 sexp
= sexp
.mid (7); // "(4:path"
5351 EXTRACT_TOKEN (sexp
, offset
, ns
, n
, path
);
5352 sexp
= sexp
.mid (7); // 7 = "5:flags"
5353 EXTRACT_TOKEN (sexp
, offset
, ns
, n
, flags
);
5354 sexp
= sexp
.mid (8); // 8 = "(5:attrs"
5355 ElementPath
*p
= new ElementPath (path
, flags
);
5356 QList
<ElementPath::ElementAttr
*> attrs
;
5359 QString name
, value
;
5360 EXTRACT_TOKEN (sexp
, offset
, ns
, n
, name
);
5361 EXTRACT_TOKEN (sexp
, offset
, ns
, n
, value
);
5362 attrs
.append (new ElementPath::ElementAttr (name
, value
));
5363 } while (!sexp
.isEmpty () && sexp
.at (0) != ')');
5365 p
->setAttrs (attrs
);
5366 elementPaths
.append (p
);
5367 sexp
= sexp
.mid (2); // 2 = "))"
5370 ui
.elementTree
->setSortingEnabled (false);
5372 foreach (ElementPath
*path
, elementPaths
)
5374 QStringList elements
= path
->path ().split ("\t");
5375 QTreeWidgetItem
*parent
= nullptr;
5376 bool nomatch
= true;
5377 QTreeWidgetItem
*item
;
5379 bool isBad
= hasFlag (path
->flags (), "EO");
5382 if (hasFlag (path
->flags (), "T"))
5384 foreach (ElementPath::ElementAttr
*a
, path
->attrs ())
5386 if (a
->name () == "_target")
5388 target
= a
->value ();
5394 for (int n
= 0; n
< elementTree
.count (); n
++)
5396 QTreeWidgetItem
*root
= elementTree
.at (n
);
5398 if (elementName (root
) == elements
.at (0))
5407 parent
= new QTreeWidgetItem ((QTreeWidget
*) 0);
5408 setItemText (parent
, elements
.at (0), !target
.isEmpty ());
5409 elementTree
.append (parent
);
5410 hasBadTarget (parent
, target
, path
->flags ());
5415 while ((item
= parent
->child (0)))
5417 if (elements
.at (element
) == elementName (item
))
5424 for (int i
= 0; i
< parent
->childCount (); i
++)
5427 tmp
= parent
->child (i
);
5429 if (elementName (parent
->child (i
)) == elements
.at (element
))
5438 if (element
== elements
.count () || nomatch
)
5446 for (; element
< elements
.count (); element
++)
5448 parent
= new QTreeWidgetItem (parent
);
5449 setItemText (parent
, elements
.at (element
), !target
.isEmpty ());
5450 hasBadTarget (parent
, target
, path
->flags ());
5455 qWarning("%s(%i): %s", __FILE__
, __LINE__
, __FUNCTION__
);
5456 /* A path has been parsed whose current element is the parent of
5457 * previously parsed element. Update the target and flags for the
5458 * previously created item, if any. */
5459 hasBadTarget (parent
, target
, path
->flags ());
5463 foreach (ElementPath::ElementAttr
*a
, path
->attrs ())
5466 setAttribute (parent
, a
->name (), a
->value (), true);
5477 PwmdMainWindow::elementPath (const QTreeWidgetItem
*item
, const QString
&sep
)
5479 QString path
= QString ();
5486 path
.prepend (QString ("%1%2").arg (sep
, elementName (item
)));
5487 item
= item
->parent ();
5491 path
.remove (0, sep
.length ());
5496 PwmdMainWindow::elementPath (const QString
&sep
)
5498 return elementPath (selectedElement
, sep
);
5502 PwmdMainWindow::slotNewRootElement ()
5504 createNewElement (true);
5508 PwmdMainWindow::slotNewSiblingElement ()
5510 createNewElement (!selectedElement
? true : false, true);
5514 PwmdMainWindow::slotNewElement ()
5518 if (selectedElement
)
5520 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
5521 if (data
->badTarget () || data
->badPermissions ())
5525 createNewElement (!selectedElement
|| b
);
5529 PwmdMainWindow::slotNewSiblingElementFromPopup ()
5531 QPoint pos
= ui
.elementTree
->mousePosition ();
5532 QTreeWidgetItem
*item
= ui
.elementTree
->itemAt (pos
.x (), pos
.y ());
5534 createNewElement (!item
? true : false, true);
5538 PwmdMainWindow::slotNewElementFromPopup ()
5540 QPoint pos
= ui
.elementTree
->mousePosition ();
5541 QTreeWidgetItem
*item
= ui
.elementTree
->itemAt (pos
.x (), pos
.y ());
5543 createNewElement (item
== nullptr);
5547 PwmdMainWindow::createNewElement (bool root
, bool sibling
)
5549 QTreeWidgetItem
*item
= selectedElement
;
5550 newElement
= nullptr;
5552 doSaveContent (true);
5553 if (!root
&& !selectedElement
)
5561 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
5562 if (data
->badPermissions ())
5568 if (sibling
&& item
)
5569 item
= item
->parent ();
5575 newElement
= new QTreeWidgetItem ((QTreeWidget
*) 0);
5576 setItemText (newElement
, tr ("New element"));
5580 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerItem
);
5581 ui
.elementTree
->addTopLevelItem (newElement
);
5583 else if (dropElement
)
5585 dropElement
->addChild (newElement
);
5586 dropElement
->setExpanded (true);
5590 item
->addChild (newElement
);
5591 item
->setExpanded (true);
5594 setElementItemsEnabled (newElement
, false);
5595 previousElement
= item
;
5596 attributeElement
= selectedElement
= newElement
;
5597 ui
.elementTree
->scrollToItem (newElement
,
5598 QAbstractItemView::PositionAtCenter
);
5599 ui
.elementTree
->editItem (newElement
);
5600 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel
);
5604 PwmdMainWindow::setModifiedContent (bool b
)
5606 setWindowModified (true);
5607 setFileModified (b
);
5611 PwmdMainWindow::deleteElementFinalize (PwmdCommandQueueItem
*cmd
)
5613 if (!cmd
->isFinalItem ())
5616 if (ui
.tabWidget
->currentWidget () != ui
.commandTab
)
5617 ui
.tabWidget
->setCurrentWidget (ui
.contentTab
);
5619 if (hasMultiSelection ())
5620 selectedElementPath
= QString ();
5623 clearAttributeTab ();
5624 refreshElementTree ();
5628 PwmdMainWindow::slotDeleteElement ()
5630 if (!selectedElement
)
5633 saveExpandedItemList ();
5634 selectedElementPath
= elementPath (ui
.elementTree
->itemBelow (selectedElement
));
5635 if (selectedElementPath
.isEmpty ())
5636 selectedElementPath
= elementPath (ui
.elementTree
->itemAbove (selectedElement
));
5638 if (selectedElementPath
.isEmpty ())
5639 selectedElement
= nullptr;
5641 QList
<QTreeWidgetItem
*> itemsToRemove
;
5642 QList
<QTreeWidgetItem
*> itemsToRemoveWithTarget
;
5643 QList
<QTreeWidgetItem
*> items
= ui
.elementTree
->selectedItems ();
5644 foreach (QTreeWidgetItem
*item
, items
)
5646 if (hasTarget (item
))
5648 if (!itemsToRemoveWithTarget
.contains (item
) && isElementOwner (item
))
5649 itemsToRemoveWithTarget
.append (item
);
5653 QTreeWidgetItem
*r
= resolveElementPath (item
);
5654 if (!itemsToRemove
.contains (r
) && isElementOwner (r
))
5655 itemsToRemove
.append (r
);
5658 items
= itemsToRemove
;
5660 foreach (QTreeWidgetItem
*item
, items
)
5662 PwmdCommandQueueItem
*cmd
;
5663 PwmdInquireData
*inq
= new PwmdInquireData (elementPath (item
));
5664 cmd
= new PwmdCommandQueueItem (PwmdCmdIdDeleteElement
, "DELETE",
5665 Pwmd::inquireCallback
, inq
);
5667 pwm
->command (cmd
, true);
5670 if (items
!= itemsToRemoveWithTarget
)
5672 items
= itemsToRemoveWithTarget
;
5680 PwmdMainWindow::slotRenameElement ()
5682 doSaveContent (true);
5684 if (!selectedElement
)
5690 setElementItemsEnabled (nullptr, false);
5691 selectedElementPath
= elementPath (selectedElement
);
5692 ui
.elementTree
->editItem (selectedElement
);
5696 PwmdMainWindow::editElements ()
5698 return refreshElementTree ();
5702 PwmdMainWindow::slotEditElements ()
5708 PwmdMainWindow::resolveElementPath (QTreeWidgetItem
* item
)
5710 QString path
= QString ();
5713 for (i
= item
; i
; i
= i
->parent ())
5715 PwmdTreeWidgetItemData
*data
=
5716 qvariant_cast
< PwmdTreeWidgetItemData
* >(i
->data (0, Qt::UserRole
));
5718 if (data
->badTarget ())
5723 path
.prepend (data
->target ());
5724 return resolveElementPath (findElement (path
));
5727 path
.prepend (elementName (i
));
5728 path
.prepend ("\t");
5731 if (path
.isEmpty ())
5734 if (path
.at (0) == '\t')
5737 return findElement (path
);
5741 PwmdMainWindow::resolveTargets (QTreeWidgetItem
* item
)
5743 return resolveElementPath (item
);
5747 PwmdMainWindow::slotResolveTargets ()
5749 QTreeWidgetItem
*i
= resolveTargets (selectedElement
);
5753 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerItem
);
5754 ui
.elementTree
->setCurrentItem (i
);
5755 selectedElement
= i
;
5756 ui
.elementTree
->scrollToItem (selectedElement
,
5757 QAbstractItemView::PositionAtCenter
);
5758 ui
.elementTree
->setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel
);
5763 PwmdMainWindow::findElement (const QString
&path
, QTreeWidgetItem
*skip
,
5764 bool any
, PwmdTreeWidget
*tree
)
5766 if (path
.isEmpty ())
5769 QStringList elements
= path
.split ("\t");
5772 tree
= ui
.elementTree
;
5773 QTreeWidgetItem
*item
= tree
->invisibleRootItem ();
5774 QTreeWidgetItem
*match
= nullptr;
5776 while (element
< elements
.count ())
5780 for (int n
= 0, t
= item
->childCount (); n
< t
; n
++)
5782 QTreeWidgetItem
*child
= item
->child (n
);
5784 if (skip
&& child
== skip
)
5787 if ((any
&& child
->text (0) == elements
.at (element
)) ||
5788 elementName (child
) == elements
.at (element
))
5790 match
= item
= child
;
5802 PwmdMainWindow::doDndCopyElement (const QString
& src
, const QString
& dst
,
5805 PwmdInquireData
*inq
= new PwmdInquireData (QString ("%1 %2").arg (src
, dst
));
5807 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdDndCopyElement
, "COPY", Pwmd::inquireCallback
, inq
);
5808 ignoreErrors (cmd
, true);
5809 pwm
->command (cmd
, queue
);
5814 PwmdMainWindow::dndCopyMoveElementFinalize (const QString
&path
)
5816 saveExpandedItemList ();
5817 selectedElementPath
= path
;
5818 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventRefreshElementTree
));
5819 QCoreApplication::postEvent (this, ev
);
5823 PwmdMainWindow::slotDndCopyElement ()
5825 dndOperation
= DndCopy
;
5826 if (doSaveContent (true))
5828 nextElement
= selectedElement
;
5835 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
5837 QString srcPath
= elementPath (item
);
5838 QString dst
= elementPath (dropElement
);
5839 int n
= srcPath
.lastIndexOf ('\t') + 1;
5841 if (dst
.isEmpty () || srcPath
!= dst
5842 || (srcPath
== dst
&& !findElement (dst
+ '\t' + dst
)))
5844 QString e
= srcPath
.mid (n
);
5849 dst
.append (QString ("\t%1").arg (e
));
5851 if (!findElement (dst
))
5854 doDndCopyElement (srcPath
, dst
, true);
5859 copyElement
= selectedElement
;
5866 createNewElement (dropElement
== nullptr);
5870 PwmdMainWindow::slotDndMoveElement ()
5872 dndOperation
= DndMove
;
5873 if (doSaveContent (true))
5875 nextElement
= selectedElement
;
5882 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
5884 if (dropElement
== item
|| isParentOf (item
, dropElement
))
5888 QString args
= QString ("%1 ").arg (elementPath (item
));
5892 s
= elementPath (dropElement
);
5893 args
.append (QString ("%1").arg (s
));
5896 PwmdInquireData
*inq
= new PwmdInquireData (args
);
5898 inq
->setUser (item
->text (0));
5900 inq
->setUser (s
+ "\t" + item
->text (0));
5902 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdDndMoveElement
, "MOVE", Pwmd::inquireCallback
, inq
);
5903 ignoreErrors (cmd
, true);
5904 pwm
->command (cmd
, true);
5909 dndOperation
= DndNone
;
5917 PwmdMainWindow::dndCreateTargetFinalize ()
5919 selectedElementPath
= elementPath (selectedElement
);
5920 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventDnDTargetAttr
));
5921 QCoreApplication::postEvent (this, ev
);
5925 PwmdMainWindow::slotDndCreateTarget ()
5927 dndOperation
= DndTarget
;
5928 if (doSaveContent (true))
5930 nextElement
= selectedElement
;
5937 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
5939 if (!dropElement
|| dropElement
== item
)
5943 QString dropPath
= elementPath (dropElement
);
5944 PwmdInquireData
*inq
= new PwmdInquireData (QString ("SET _target %1 %2").arg (elementPath (item
), dropPath
));
5945 inq
->setUser (dropPath
);
5946 inq
->setUserPtr (item
);
5947 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdDndCreateTarget
, "ATTR", Pwmd::inquireCallback
, inq
);
5948 ignoreErrors (cmd
, true);
5949 pwm
->command (cmd
, true);
5954 dndOperation
= DndNone
;
5962 PwmdMainWindow::isParentOf (QTreeWidgetItem
* a
, QTreeWidgetItem
* b
)
5979 recurseExpand (QTreeWidgetItem
* item
, bool b
)
5981 item
->setExpanded (b
);
5983 for (int i
= 0; i
< item
->childCount (); i
++)
5985 QTreeWidgetItem
*tmp
= item
->child (i
);
5987 recurseExpand (tmp
, b
);
5992 PwmdMainWindow::slotExpandElement ()
5995 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
5996 recurseExpand (item
, true);
6001 PwmdMainWindow::slotCollapseElement ()
6003 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
6004 recurseExpand (item
, false);
6008 PwmdMainWindow::slotMenuItemHovered (QAction
* a
)
6010 QStatusBar
*sb
= statusBar ();
6011 sb
->showMessage (a
->statusTip ());
6015 PwmdMainWindow::popupContextMenu ()
6017 QTreeWidgetItem
*item
= selectedElement
;
6019 selectedElement
= ui
.elementTree
->currentItem ();
6020 selectedAttribute
= ui
.attributeList
->currentItem ();
6022 PwmdTreeWidgetItemData
*data
= nullptr;
6024 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(selectedElement
->data (0, Qt::UserRole
));
6026 QMenu
*m
= new QMenu (this);
6027 connect (m
, SIGNAL (hovered (QAction
*)), this,
6028 SLOT (slotMenuItemHovered (QAction
*)));
6029 QAction
*a
= m
->addAction (tr ("New &root element"), this,
6030 SLOT (slotNewRootElement ()));
6031 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuNewRoot
, false, false, true));
6032 a
= m
->addAction (tr ("&New child element"), this,
6033 SLOT (slotNewElementFromPopup ()));
6034 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuNew
, false, false, true));
6035 a
= m
->addAction (tr ("New &sibling element"), this,
6036 SLOT (slotNewSiblingElementFromPopup ()));
6037 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuNewSibling
, false, false, true));
6038 a
= m
->addAction (tr ("Rena&me"), this, SLOT (slotRenameElement ()));
6039 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuRename
, false, false, true));
6040 a
= m
->addAction (tr ("&Delete"), this, SLOT (slotDeleteElement ()));
6041 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuDelete
, false, false, true));
6044 if (ui
.tabWidget
->currentWidget () != ui
.contentTab
)
6045 a
= m
->addAction (tr ("&Edit content"), this,
6046 SLOT (slotEditContent ()));
6048 a
= m
->addAction (tr ("&Edit attributes"), this,
6049 SLOT (slotEditAttributes ()));
6050 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuEditContent
, false, false, true));
6051 a
= m
->addAction (tr ("Resolve &targets"), this,
6052 SLOT (slotResolveTargets ()));
6053 a
->setEnabled (fixupMenu (ui
.menuElement
, ElementMenuResolveTargets
, false, false, true));
6056 a
= m
->addAction (tr ("E&xpand"), this, SLOT (slotExpandElement ()));
6057 a
->setEnabled (fixupMenu (ui
.menuView
, ViewMenuExpandAll
, false, false, true));
6058 a
->setEnabled (item
&& !data
->badPermissions () && !data
->badTarget ());
6059 a
= m
->addAction (tr ("Colla&pse"), this, SLOT (slotCollapseElement ()));
6060 a
->setEnabled (item
&& !data
->badPermissions () && !data
->badTarget ());
6061 a
= m
->addAction (tr ("Cop&y element path"), this,
6062 SLOT (slotClipboardElementPath ()));
6063 a
->setEnabled (item
);
6065 m
->exec (QCursor::pos ());
6070 PwmdMainWindow::isInvoker ()
6072 return !connectedUser
.isEmpty() && !invokingUser
.isEmpty ()
6073 && invokingUser
.indexOf (connectedUser
) != -1;
6077 PwmdMainWindow::isElementOwner (QTreeWidgetItem
*item
, bool secondary
)
6085 PwmdTreeWidgetItemData
*data
= item
? qvariant_cast
<PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
)) : nullptr;
6088 QString acl
= data
->attribute("_acl");
6089 QStringList list
= acl
.split(",");
6091 if (!list
.isEmpty ()
6092 && (list
.at(0) == connectedUser
|| list
.at(0).isEmpty ()))
6097 foreach (QString user
, list
)
6099 if (user
== connectedUser
)
6109 PwmdMainWindow::setTimeLabels (QTreeWidgetItem
* item
, bool needsRefresh
)
6113 ui
.l_ctime
->setText (tr ("-"));
6114 ui
.l_mtime
->setText (tr ("-"));
6118 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6121 if (item
== attributeElement
)
6123 ui
.l_ctime
->setText (tr("click refresh to update"));
6124 ui
.l_mtime
->setText (tr("click refresh to update"));
6127 data
->setNeedsAttrRefresh ();
6131 QString s
= data
->attribute ("_ctime");
6132 unsigned t
= s
.toUInt ();
6135 date
.setSecsSinceEpoch (t
);
6136 ui
.l_ctime
->setText (!s
.isEmpty () ? date
.toString () : tr ("-"));
6137 s
= data
->attribute ("_mtime");
6139 date
.setSecsSinceEpoch (t
);
6140 ui
.l_mtime
->setText (!s
.isEmpty () ? date
.toString () : tr ("-"));
6144 PwmdMainWindow::slotEditTargetAttributes (bool b
)
6146 if (doSaveContent (true))
6148 editTargetAttributes
= b
;
6149 disconnect (ui
.actionToggleTargetAttribute
, SIGNAL (triggered (bool)), this, SLOT (slotEditTargetAttributes(bool)));
6150 ui
.actionToggleTargetAttribute
->setChecked (!b
);
6151 connect (ui
.actionToggleTargetAttribute
, SIGNAL (triggered (bool)), this, SLOT (slotEditTargetAttributes(bool)));
6156 editAttributes (b
, selectedElement
);
6160 PwmdMainWindow::fixupEditContentOrAttributes (bool attrs
)
6164 disconnect (ui
.actionEditContentOrAttributes
, SIGNAL (triggered()), this, SLOT (slotEditContent ()));
6165 ui
.actionEditContentOrAttributes
->setText (tr ("&Edit attributes"));
6166 connect (ui
.actionEditContentOrAttributes
, SIGNAL (triggered()), this, SLOT (slotEditAttributes ()));
6170 disconnect (ui
.actionEditContentOrAttributes
, SIGNAL (triggered()), this, SLOT (slotEditAttributes ()));
6171 ui
.actionEditContentOrAttributes
->setText (tr ("&Edit content"));
6172 connect (ui
.actionEditContentOrAttributes
, SIGNAL (triggered()), this, SLOT (slotEditContent ()));
6176 PwmdMainWindow::slotEditAttributes ()
6178 fixupEditContentOrAttributes ();
6179 targetAttributeElement
= nullptr;
6180 ui
.actionToggleTargetAttribute
->setChecked (false);
6181 editAttributes (false, selectedElement
);
6185 PwmdMainWindow::setElementColors (QTreeWidgetItem
*item
, bool reset
,
6188 PwmdTreeWidgetItemData
*data
= nullptr;
6190 if (targetAttributeElement
&& target
)
6194 QBrush b
= targetAttributeElement
->foreground (0);
6195 QBrush
bg(QPalette::Window
);
6197 b
.setColor (hilightColor
);
6198 targetAttributeElement
->setForeground (0, b
);
6199 bg
.setColor(hilightColorBg
);
6200 targetAttributeElement
->setBackground(0, bg
);
6207 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6213 if (targetAttributeElement
)
6215 item
= targetAttributeElement
;
6221 if (data
->badPermissions ())
6223 QBrush br
= item
->foreground (0);
6224 QBrush
bg(QPalette::Window
);
6226 br
.setColor (permissionsColor
);
6227 item
->setForeground (0, br
);
6228 bg
.setColor(permissionsColorBg
);
6229 item
->setBackground(0, bg
);
6231 else if (data
->targetLoop ())
6233 QBrush br
= item
->foreground (0);
6234 QBrush
bg(QPalette::Window
);
6236 bg
.setColor(targetLoopColorBg
);
6237 item
->setBackground(0, bg
);
6239 br
.setColor (targetLoopColor
);
6240 item
->setForeground (0, br
);
6242 else if (data
->badTarget ())
6244 QBrush br
= item
->foreground (0);
6245 QBrush
bg(QPalette::Window
);
6247 bg
.setColor(invalidTargetColorBg
);
6248 item
->setBackground(0, bg
);
6250 br
.setColor (invalidTargetColor
);
6251 item
->setForeground (0, br
);
6253 else if (data
->hasTarget ())
6255 QBrush br
= item
->foreground (0);
6256 QBrush
bg(QPalette::Window
);
6258 bg
.setColor(targetColorBg
);
6259 item
->setBackground(0, bg
);
6261 br
.setColor (targetColor
);
6262 item
->setForeground (0, br
);
6266 QBrush
b (QPalette::Text
);
6267 b
.setColor ("Black");
6268 item
->setForeground (0, b
);
6269 b
.setColor ("White");
6270 item
->setBackground (0, b
);
6273 if (item
!= targetAttributeElement
)
6275 item
= targetAttributeElement
;
6276 targetAttributeElement
= nullptr;
6277 ui
.actionToggleTargetAttribute
->setChecked (false);
6278 editTargetAttributes
= false;
6284 PwmdMainWindow::editAttributes (bool resolve
, QTreeWidgetItem
*item
)
6286 if (doSaveContent (true))
6288 editTargetAttributes
= resolve
;
6295 fixupMenu (ui
.menuAttributes
, AttributeMenuTarget
,
6296 hasTarget (item
) && !badTarget (item
),
6297 hasTarget (item
) && !badTarget (item
)
6298 && ui
.actionToggleTargetAttribute
->isChecked ());
6303 editTargetAttributes
= resolve
;
6304 setElementItemsEnabled (item
, item
);
6305 QTreeWidgetItem
*titem
= !resolve
? item
: resolveTargets (item
);
6306 targetAttributeElement
= resolve
? titem
: targetAttributeElement
;
6307 attributeElement
= titem
? titem
: item
;
6309 PwmdTreeWidgetItemData
*data
= attributeElement
? qvariant_cast
< PwmdTreeWidgetItemData
* >(attributeElement
->data (0, Qt::UserRole
)) : nullptr;
6310 if (!resolve
&& data
)
6312 if (data
->badPermissions () && data
->hasTarget ())
6313 attributeElement
= findElement (elementPath (attributeElement
));
6316 refreshAttributeList (attributeElement
);
6317 setAttributeItemsEnabled ();
6318 ui
.attributeList
->setCurrentRow (previousAttributeIndex ());
6319 setElementColors (targetAttributeElement
, !resolve
, true);
6320 ui
.elementTree
->scrollToItem (attributeElement
);
6324 PwmdMainWindow::slotAttrSearchAndReplaceChanged (const QString
&)
6326 ui
.pb_searchAndReplace
->setEnabled (ui
.cb_searchAndReplace
->lineEdit ()->hasAcceptableInput ());
6330 PwmdMainWindow::slotAttrSearchAndReplace ()
6332 QString str
= ui
.cb_searchAndReplace
->lineEdit ()->text ();
6333 bool escaped
= false;
6334 bool doingReplace
= false;
6335 QString pattern
, replace
;
6337 foreach (QChar c
, str
.mid (1))
6339 if (doingReplace
|| (c
== '/' && !escaped
))
6342 doingReplace
= true;
6355 escaped
= c
== '\\';
6360 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
6362 searchAndReplace
= true;
6363 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(item
->data (0, Qt::UserRole
));
6364 QString value
= data
->attribute (selectedAttribute
->text ());
6365 QRegularExpression
rx (pattern
);
6366 QRegularExpressionMatch match
= rx
.match (value
);
6367 if (match
.hasMatch ()) {
6368 value
.replace (rx
, replace
);
6369 while (value
.endsWith (','))
6372 setAttributeContentOnce (item
, elementPath (item
), value
, false,
6374 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, true);
6378 ui
.cb_searchAndReplace
->lineEdit ()->setText ("");
6383 PwmdMainWindow::slotRefreshAttributes ()
6385 refreshAttributeList (attributeElement
, true);
6389 PwmdMainWindow::clearAttributeTab ()
6391 setTimeLabels (nullptr);
6392 disconnect (ui
.attributeContent
, SIGNAL (modificationChanged (bool)), this,
6393 SLOT (slotContentModified (bool)));
6394 disconnect (ui
.attributeContent
, SIGNAL (textChanged ()), this, SLOT (slotContentChanged ()));
6395 ui
.attributeContent
->document()->setPlainText ("");
6396 ui
.attributeList
->clear ();
6397 connect (ui
.attributeContent
, SIGNAL (textChanged ()), SLOT (slotContentChanged ()));
6398 connect (ui
.attributeContent
, SIGNAL (modificationChanged (bool)), this,
6399 SLOT (slotContentModified (bool)));
6403 PwmdMainWindow::refreshAttributeListFinalize (QTreeWidgetItem
*element
,
6404 const QString
&result
,
6405 bool create
, bool fromTree
)
6407 if (create
&& !createAttributeCache (element
, result
))
6410 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(element
->data (0, Qt::UserRole
));
6411 PwmdAttributeList
*attrs
= data
->attributes ();
6412 QList
<QListWidgetItem
*> items
;
6414 for (int i
= 0, t
= attrs
->count (); i
< t
; i
++)
6416 PwmdElementAttr
*attr
= attrs
->at (i
);
6417 QListWidgetItem
*item
= new QListWidgetItem (attr
->name ());
6419 if (PwmdElementAttr::isProtectedAttribute (attr
->name ()))
6420 item
->setFlags (~(item
->flags () & Qt::ItemIsEnabled
));
6422 items
.append (item
);
6425 if (!editTargetAttributes
&& !fromTree
)
6426 selectedElement
= attributeElement
= element
;
6428 if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
6429 && (element
== attributeElement
|| element
== targetAttributeElement
6430 || element
== ui
.elementTree
->currentItem ()))
6432 setAttributeContent ("");
6433 selectedAttribute
= nullptr;
6434 clearAttributeTab ();
6435 data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(element
->data (0, Qt::UserRole
));
6437 foreach (QListWidgetItem
*item
, items
)
6439 if (!PwmdElementAttr::isReservedAttribute (item
->text ())
6440 && data
->hasTarget ())
6442 QBrush b
= item
->foreground ();
6443 QBrush
bg(QPalette::Window
);
6445 b
.setColor (hilightColor
);
6446 item
->setForeground (b
);
6447 bg
.setColor(hilightColorBg
);
6448 item
->setBackground(bg
);
6451 ui
.attributeList
->addItem (item
);
6454 setTimeLabels (element
, data
->needsAttrRefresh ());
6456 else if (ui
.tabWidget
->currentWidget () == ui
.contentTab
6457 && element
== selectedElement
)
6459 foreach (QListWidgetItem
*item
, items
)
6464 foreach (QListWidgetItem
*item
, items
)
6468 if (isElementOwner (element
))
6469 element
->setFlags (element
->flags () | Qt::ItemIsEditable
);
6471 fixupToolBar (attributeToolBar
, AttributeToolBarOk
, false);
6472 ui
.attributeList
->setCurrentRow (previousAttributeIndex ());
6474 /* The item attributes are wanted during a DnD operation. Emit a signal
6475 to tell the element tree that certain popup context menu items may be
6479 AttributesRetrievedEvent
*ev
= new AttributesRetrievedEvent
6480 (QEvent::Type (PwmdEventAttrsRetrieved
));
6481 ev
->setItem (element
);
6482 QCoreApplication::postEvent (this, ev
);
6487 PwmdMainWindow::refreshAttributeList (QTreeWidgetItem
*item
, bool force
,
6488 bool queue
, bool fromTree
)
6492 clearAttributeTab ();
6496 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6497 if (!data
->attributes ()->isEmpty () && !force
)
6499 refreshAttributeListFinalize (item
, QString (), false, fromTree
);
6505 if (!fromTree
&& item
!= selectedElement
)
6506 clearAttributeTab ();
6508 PwmdInquireData
*inq
= new PwmdInquireData (QString ("LIST %1").arg (elementPath (item
)));
6509 inq
->setUserPtr (item
);
6510 inq
->setUserBool (fromTree
);
6511 pwm
->command (new PwmdCommandQueueItem (PwmdCmdIdAttrList
, "ATTR",
6512 Pwmd::inquireCallback
, inq
), queue
);
6517 PwmdMainWindow::slotAttributeEditorClosed (QWidget
* w
,
6518 QAbstractItemDelegate::EndEditHint h
)
6520 QLineEdit
*le
= qobject_cast
< QLineEdit
* >(w
);
6521 QString s
= le
->text ();
6524 if (le
->text () == tr ("New attribute") || le
->text ().isEmpty () ||
6525 h
== QAbstractItemDelegate::RevertModelCache
6526 || (le
->validator() && le
->validator()->validate (s
, pos
) == QValidator::Invalid
))
6528 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewAttributeCancel
));
6529 QCoreApplication::postEvent (this, ev
);
6534 /* Update element attributes for all items that have a target to "item", or
6535 * just the "item" itself. */
6537 PwmdMainWindow::updateTargetAttributes (QTreeWidgetItem
*item
,
6538 const QString
&name
,
6539 const QString
&value
, bool remove
)
6541 /* Cannot set time attributes and other reserved attributes require a tree
6543 if (PwmdElementAttr::isReservedAttribute (name
))
6546 QTreeWidgetItem
*t
= resolveTargets (item
);
6550 foreach (QTreeWidgetItem
*e
, ui
.elementTree
->findItems ("*",
6552 |Qt::MatchWildcard
))
6554 if (resolveTargets (e
) != t
)
6558 removeAttribute (e
, name
);
6560 setAttribute (e
, name
, value
);
6563 setTimeLabels (t
, true);
6567 PwmdMainWindow::setNewAttributeFinalize (AttributeFinalizeT
*attr
,
6570 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(attr
->item
->data (0, Qt::UserRole
));
6571 setAttribute (attr
->item
, attr
->name
, attr
->content
, true);
6574 if (attr
->item
!= selectedElement
&& attr
->item
!= attributeElement
)
6577 if (attr
->name
== "password"
6578 && ui
.tabWidget
->currentWidget() == ui
.contentTab
)
6580 elementSelected (selectedElement
);
6583 else if (attr
->name
== "_expire"
6584 && ui
.tabWidget
->currentWidget () == ui
.contentTab
)
6586 setElementExpireLabel (attr
->content
.toUInt ());
6587 setContentItemsEnabled ();
6589 else if (attr
->name
== "hidden")
6591 ui
.textEdit
->setHidden (true);
6592 ui
.hiddenContentFrame
->setHidden (data
->hasAttribute ("password"));
6593 disconnect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
6594 ui
.actionHidden
->setChecked (true);
6595 connect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
6597 else if (attr
->name
== "encoding" && attr
->content
== "base64")
6599 disconnect (ui
.actionBase64
, SIGNAL (triggered(bool)), this, SLOT (slotToggleBase64Content(bool)));
6600 ui
.actionBase64
->setChecked (true);
6601 connect (ui
.actionBase64
, SIGNAL (triggered(bool)), this, SLOT (slotToggleBase64Content(bool)));
6604 if (!attr
->listItem
)
6607 Qt::ItemFlags flags
= attr
->listItem
->flags();
6608 flags
&= ~Qt::ItemIsEditable
;
6609 attr
->listItem
->setFlags(flags
);
6611 if (ui
.tabWidget
->currentWidget () == ui
.attributeTab
)
6613 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(attr
->item
->data (0, Qt::UserRole
));
6614 if (!PwmdElementAttr::isReservedAttribute (attr
->listItem
->text ())
6615 && data
->hasTarget ())
6617 QBrush b
= attr
->listItem
->foreground ();
6618 QBrush
bg(QPalette::Window
);
6620 b
.setColor (hilightColor
);
6621 attr
->listItem
->setForeground (b
);
6622 bg
.setColor(hilightColorBg
);
6623 attr
->listItem
->setBackground(bg
);
6627 if (fromSlot
&& (attr
->item
== selectedElement
6628 || attr
->item
== attributeElement
))
6630 slotAttributeSelected (attr
->listItem
, nullptr);
6631 ui
.attributeList
->setCurrentItem (attr
->listItem
);
6633 if (attr
->name
== "password")
6634 elementSelected (selectedElement
);
6639 PwmdMainWindow::setNewAttribute (QTreeWidgetItem
*item
, QString name
,
6640 QString value
, bool fromSlot
, bool queue
)
6642 PwmdInquireData
*inq
= new PwmdInquireData (QString ("SET %1 %2 %3").arg (name
, elementPath (item
), value
));
6644 AttributeFinalizeT
*attr
= new AttributeFinalizeT
;
6646 attr
->listItem
= newAttribute
? newAttribute
->clone () : nullptr;
6648 attr
->content
= value
;
6649 inq
->setUserPtr (attr
);
6650 inq
->setUserBool (fromSlot
);
6651 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdAttrNew
,
6653 Pwmd::inquireCallback
,
6656 return pwm
->command (cmd
, queue
);
6660 PwmdMainWindow::attributeIsEditable (QTreeWidgetItem
*item
,
6661 QListWidgetItem
*attr
)
6666 PwmdTreeWidgetItemData
*data
= nullptr;
6667 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6671 if (attr
->text() == "password")
6674 if (PwmdElementAttr::isReservedAttribute (attr
->text ()))
6675 return isElementOwner (item
);
6677 return !data
->hasError () && isElementOwner (item
);
6681 PwmdMainWindow::slotAttributeSelected (QListWidgetItem
*item
, QListWidgetItem
*)
6683 if (ui
.tabWidget
->currentWidget () != ui
.attributeTab
)
6686 PwmdTreeWidgetItemData
*data
= nullptr;
6687 if (attributeElement
)
6688 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(attributeElement
->data (0, Qt::UserRole
));
6690 ui
.attributeContent
->setEnabled (item
&& (item
->flags() & Qt::ItemIsEnabled
));
6691 setAttributeItemsEnabled ();
6693 doSaveContent (true);
6700 if (!(item
->flags () & Qt::ItemIsEnabled
))
6702 ui
.attributeList
->setCurrentItem (selectedAttribute
);
6707 selectedAttribute
= item
;
6708 previousAttributeText
= item
->text ();
6709 QTreeWidgetItem
*i
= attributeElement
;
6710 data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(i
->data (0, Qt::UserRole
));
6711 QString s
= data
->attribute (item
->text ());
6712 setAttributeContent (s
.isEmpty ()? "" : s
.replace ("\t", "<TAB>", Qt::CaseInsensitive
));
6714 if (item
&& item
->text () == "_target")
6715 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
, false);
6716 else if (item
&& item
->text () == "_acl" && isElementOwner (selectedElement
))
6717 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
, true);
6719 ui
.attributeContent
->setReadOnly (!attributeIsEditable (attributeElement
, item
));
6723 PwmdMainWindow::slotConfirmNewAttribute (QWidget
* w
)
6725 QLineEdit
*le
= qobject_cast
< QLineEdit
* >(w
);
6730 PwmdTreeWidgetItemData
*data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(attributeElement
->data (0, Qt::UserRole
));
6732 if (le
->text () == tr ("New attribute")
6733 || le
->text ().isEmpty ()
6734 || PwmdElementAttr::isProtectedAttribute (le
->text ()))
6736 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewAttributeCancel
));
6737 QCoreApplication::postEvent (this, ev
);
6742 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
6744 QTreeWidgetItem
*ritem
= resolveTargets (item
);
6745 data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(item
->data (0, Qt::UserRole
));
6746 if (!data
->hasAttribute (le
->text ())
6747 && attributeIsEditable (item
, newAttribute
))
6749 data
= qvariant_cast
<PwmdTreeWidgetItemData
*>(ritem
->data (0, Qt::UserRole
));
6751 || (attributeIsEditable (ritem
, newAttribute
)
6752 && !data
->hasAttribute (le
->text ())))
6755 setNewAttribute (item
, le
->text (), QString (), true, true);
6760 delete newAttribute
;
6761 newAttribute
= nullptr;
6764 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventNewAttributeCancel
));
6765 QCoreApplication::postEvent (this, ev
);
6772 PwmdMainWindow::slotNewAttribute ()
6774 if (doSaveContent (true))
6776 newAttribute
= new QListWidgetItem (tr ("New attribute"));
6781 setAttributeContent ("");
6782 ui
.attributeContent
->setEnabled (false);
6783 fixupToolBar (attributeToolBar
, AttributeToolBarNew
, false);
6784 fixupToolBar (attributeToolBar
, AttributeToolBarDelete
, false);
6785 delete newAttribute
;
6786 newAttribute
= new QListWidgetItem (tr ("New attribute"));
6787 newAttribute
->setFlags (newAttribute
->flags () | Qt::ItemIsEditable
);
6788 ui
.attributeList
->addItem (newAttribute
);
6789 ui
.attributeList
->scrollToItem (newAttribute
);
6790 ui
.attributeList
->editItem (newAttribute
);
6794 PwmdMainWindow::slotDeleteAttribute ()
6796 if (!selectedAttribute
6797 || !(selectedAttribute
->flags () & Qt::ItemIsEnabled
))
6801 doSaveContent (true);
6802 foreach (QTreeWidgetItem
*item
, ui
.elementTree
->selectedItems ())
6804 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6805 QString attr
= selectedAttribute
->text ();
6806 QTreeWidgetItem
*ritem
= resolveTargets (item
);
6808 if (data
->hasAttribute (attr
) &&
6809 ((!PwmdElementAttr::isReservedAttribute (attr
) || attr
== "_acl")
6810 && isElementOwner (item
)))
6812 if (ritem
== item
|| isElementOwner (ritem
))
6813 deleteAttribute (item
, attr
, true);
6821 PwmdMainWindow::setAttribute (QTreeWidgetItem
*item
, const QString
&name
,
6822 const QString
&value
, bool update
)
6827 PwmdTreeWidgetItemData
*data
=
6828 qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6833 data
->addAttribute (name
, value
);
6835 updateTargetAttributes (item
, name
, value
);
6837 refreshAttributeListFinalize (item
, QString (), false);
6841 PwmdMainWindow::removeAttribute (QTreeWidgetItem
* item
, const QString
& name
,
6844 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6846 data
->removeAttribute (name
);
6847 data
->setNeedsAttrRefresh ();
6849 updateTargetAttributes (item
, name
, QString (), true);
6853 PwmdMainWindow::deleteAttributeFinalize (QTreeWidgetItem
*item
,
6854 const QString
&name
)
6856 removeAttribute (item
, name
, true);
6858 if (item
!= selectedElement
)
6861 PwmdTreeWidgetItemData
*data
= qvariant_cast
< PwmdTreeWidgetItemData
* >(item
->data (0, Qt::UserRole
));
6863 if (name
== "_expire" && ui
.tabWidget
->currentWidget () == ui
.contentTab
)
6864 setContentItemsEnabled ();
6865 else if (name
== "hidden")
6867 ui
.textEdit
->setHidden (data
->hasAttribute ("password"));
6868 ui
.hiddenContentFrame
->setHidden (true);
6869 disconnect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
6870 ui
.actionHidden
->setChecked (false);
6871 connect (ui
.actionHidden
, SIGNAL (toggled(bool)), this, SLOT (slotToggleHiddenContent(bool)));
6873 else if (name
== "encoding" && data
->attribute ("encoding") != "base64")
6875 disconnect (ui
.actionBase64
, SIGNAL (triggered(bool)), this, SLOT (slotToggleBase64Content(bool)));
6876 ui
.actionBase64
->setChecked (false);
6877 connect (ui
.actionBase64
, SIGNAL (triggered(bool)), this, SLOT (slotToggleBase64Content(bool)));
6880 if (item
== selectedElement
|| item
== attributeElement
)
6882 if (selectedAttribute
)
6883 delete selectedAttribute
;
6885 selectedAttribute
= ui
.attributeList
->currentItem ();
6886 setAttributeContent ("");
6888 if (name
== "_target")
6890 selectedElementPath
= elementPath (attributeElement
);
6891 QEvent
*ev
= new QEvent (QEvent::Type (PwmdEventTargetAttr
));
6892 QCoreApplication::postEvent (this, ev
);
6895 elementSelected (selectedElement
);
6900 PwmdMainWindow::deleteAttribute (QTreeWidgetItem
*item
, const QString
&name
,
6903 PwmdInquireData
*inq
= new PwmdInquireData (QString ("DELETE %1 %2").arg (name
, elementPath (item
)));
6905 inq
->setUserPtr (item
);
6906 inq
->setUser (name
);
6907 PwmdCommandQueueItem
*cmd
= new PwmdCommandQueueItem (PwmdCmdIdAttrDelete
,
6909 Pwmd::inquireCallback
,
6912 return pwm
->command (cmd
, queue
);
6916 PwmdMainWindow::hasMultiSelection ()
6918 return ui
.elementTree
->selectedItems ().count () > 1;
6922 PwmdMainWindow::hasSingleSelection ()
6924 return !hasMultiSelection ();
6928 PwmdMainWindow::firstSelectedItem ()
6930 return ui
.elementTree
->selectedItems ().count ()
6931 ? ui
.elementTree
->selectedItems ().at (0) : nullptr;