1 // -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
2 /* This file is part of the KDE project
3 Copyright (C) 2000 by Carsten Pfeiffer <pfeiffer@kde.org>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 #include <QPushButton>
23 #include <QHeaderView>
27 #include <kshortcutsdialog.h>
28 #include <KServiceTypeTrader>
30 #include "configdialog.h"
32 ConfigDialog::ConfigDialog(QWidget
*parent
, KConfigSkeleton
*skeleton
, const ActionList
*list
, KActionCollection
*collection
,
34 : KConfigDialog(parent
, "preferences", skeleton
)
37 setHelp( QString(), "klipper" );
39 QWidget
*w
= 0; // the parent for the widgets
41 w
= new QWidget(this);
42 generalWidget
= new GeneralWidget(w
);
43 addPage(generalWidget
, i18nc("General Config", "General"), "klipper", i18n("General Config"));
45 w
= new QWidget(this);
46 actionWidget
= new ActionWidget(list
, w
);
47 addPage(actionWidget
, i18nc("Actions Config", "Actions"), "system-run", i18n("Actions Config"));
49 w
= new QWidget(this);
50 shortcutsWidget
= new KShortcutsEditor( collection
, w
, KShortcutsEditor::GlobalAction
);
51 addPage(shortcutsWidget
, i18nc("Shortcuts Config", "Shortcuts"), "configure-shortcuts", i18n("Shortcuts Config"));
55 ConfigDialog::~ConfigDialog()
59 void ConfigDialog::commitShortcuts()
61 //keysWidget->commitChanges();
64 GeneralWidget::GeneralWidget( QWidget
*parent
)
67 QVBoxLayout
*mainLayout
= new QVBoxLayout(this);
69 cbMousePos
= new QCheckBox(i18n("&Popup menu at mouse-cursor position"), this);
70 mainLayout
->addWidget(cbMousePos
);
72 cbSaveContents
= new QCheckBox(i18n("Save clipboard contents on e&xit"), this);
73 mainLayout
->addWidget(cbSaveContents
);
75 cbStripWhitespace
= new QCheckBox(i18n("Remove whitespace when executing actions"), this);
76 cbStripWhitespace
->setWhatsThis(i18n("Sometimes, the selected text has some whitespace at the end, which, "
77 "if loaded as URL in a browser would cause an error. Enabling this option "
78 "removes any whitespace at the beginning or end of the selected string (the original "
79 "clipboard contents will not be modified)."));
80 mainLayout
->addWidget(cbStripWhitespace
);
82 cbReplayAIH
= new QCheckBox(i18n("&Replay actions on an item selected from history"), this);
83 mainLayout
->addWidget(cbReplayAIH
);
85 cbNoNull
= new QCheckBox(i18n("Pre&vent empty clipboard"), this);
86 cbNoNull
->setWhatsThis(i18n("Selecting this option has the effect, that the "
87 "clipboard can never be emptied. E.g. when an application "
88 "exits, the clipboard would usually be emptied."));
89 mainLayout
->addWidget(cbNoNull
);
91 cbIgnoreSelection
= new QCheckBox(i18n("&Ignore selection"), this);
92 cbIgnoreSelection
->setWhatsThis(i18n("This option prevents the selection being recorded "
93 "in the clipboard history. Only explicit clipboard "
94 "changes are recorded."));
95 mainLayout
->addWidget(cbIgnoreSelection
);
97 QGroupBox
*group
= new QGroupBox(i18n("Clipboard/Selection Behavior"), this);
98 group
->setWhatsThis(i18n("<qt>There are two different clipboard buffers available:<br /><br />"
99 "<b>Clipboard</b> is filled by selecting something "
100 "and pressing Ctrl+C, or by clicking \"Copy\" in a toolbar or "
101 "menubar.<br /><br />"
102 "<b>Selection</b> is available immediately after "
103 "selecting some text. The only way to access the selection "
104 "is to press the middle mouse button.<br /><br />"
105 "You can configure the relationship between Clipboard and Selection."
107 mainLayout
->addWidget(group
);
109 QVBoxLayout
*groupLayout
= new QVBoxLayout(group
);
111 cbSynchronize
= new QRadioButton(i18n("Sy&nchronize contents of the clipboard and the selection"), group
);
112 cbSynchronize
->setWhatsThis(i18n("Selecting this option synchronizes these two buffers."));
113 connect(cbSynchronize
, SIGNAL(clicked()), SLOT(slotClipConfigChanged()));
114 groupLayout
->addWidget(cbSynchronize
);
116 cbSeparate
= new QRadioButton(i18n("Separate clipboard and selection"), group
);
117 cbSeparate
->setWhatsThis(i18n("Using this option will only set the selection when highlighting "
118 "something and the clipboard when choosing e.g. \"Copy\" "
120 connect(cbSeparate
, SIGNAL(clicked()), SLOT(slotClipConfigChanged()));
121 groupLayout
->addWidget(cbSeparate
);
123 cbSeparate
->setChecked(!cbSynchronize
->isChecked());
125 popupTimeout
= new KIntNumInput(this);
126 popupTimeout
->setLabel(i18n("Tim&eout for action popups:"));
127 popupTimeout
->setRange(0, 200);
128 popupTimeout
->setSuffix(i18n(" sec"));
129 popupTimeout
->setToolTip(i18n("A value of 0 disables the timeout"));
130 mainLayout
->addWidget(popupTimeout
);
132 maxItems
= new KIntNumInput(this);
133 maxItems
->setLabel(i18n("C&lipboard history size:"));
134 maxItems
->setRange(2, 2048);
135 connect(maxItems
, SIGNAL(valueChanged(int)), SLOT(historySizeChanged(int)));
136 mainLayout
->addWidget(maxItems
);
138 slotClipConfigChanged();
141 GeneralWidget::~GeneralWidget()
145 void GeneralWidget::historySizeChanged( int value
)
147 // Note there is no %n in this string, because value is not supposed
148 // to be put into the suffix of the spinbox.
149 maxItems
->setSuffix( i18np( " entry", " entries", value
) );
152 void GeneralWidget::slotClipConfigChanged()
154 cbIgnoreSelection
->setEnabled( !cbSynchronize
->isChecked() );
157 // it does not make sense to port / enable this since KRegExpEditor is in a very bad shape. just keep this
158 // code here because it will probably help at a later point to port it when KRegExpEditor is again usable.
159 // 2007-10-20, uwolfer
161 void ListView::rename( Q3ListViewItem
* item
, int c
)
164 if ( item
->childCount() != 0 && c
== 0) {
165 // This is the regular expression
166 if ( _configWidget
->useGUIRegExpEditor() ) {
172 if ( ! _regExpEditor
)
173 _regExpEditor
= KServiceTypeTrader::createInstanceFromQuery
<QDialog
>( "KRegExpEditor/KRegExpEditor", QString(), this );
174 KRegExpEditorInterface
*iface
= qobject_cast
<KRegExpEditorInterface
*>(_regExpEditor
);
177 iface
->setRegExp( item
->text( 0 ) );
179 bool ok
= _regExpEditor
->exec();
181 item
->setText( 0, iface
->regExp() );
184 K3ListView::rename( item
,c
);
188 ActionWidget::ActionWidget( const ActionList
*list
, QWidget
*parent
)
194 QVBoxLayout
*mainLayout
= new QVBoxLayout(this);
196 QLabel
*lblAction
= new QLabel(i18n("Action &list (right click to add/remove commands):"), this);
197 mainLayout
->addWidget(lblAction
);
199 treeWidget
= new QTreeWidget(this);
200 lblAction
->setBuddy(treeWidget
);
202 treeWidget
->setHeaderLabels(QStringList() << i18n("Regular Expression") << i18n("Description"));
203 treeWidget
->header()->resizeSection(0, 250);
204 treeWidget
->setSelectionBehavior(QTreeWidget::SelectRows
);
205 treeWidget
->setSelectionMode(QTreeWidget::SingleSelection
);
207 mainLayout
->addWidget(treeWidget
);
209 ClipAction
*action
= 0L;
210 ClipCommand
*command
= 0L;
212 ActionListIterator
it( *list
);
214 while (it
.hasNext()) {
217 QTreeWidgetItem
*item
= new QTreeWidgetItem(treeWidget
,
218 QStringList() << action
->regExp() << action
->description());
219 item
->setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsEnabled
);
221 QListIterator
<ClipCommand
*> it2( action
->commands() );
222 while (it2
.hasNext()) {
223 command
= it2
.next();
225 QTreeWidgetItem
*child
= new QTreeWidgetItem(item
, QStringList()
226 << command
->command
<< command
->description
);
227 child
->setIcon(0, KIcon(command
->pixmap
.isEmpty() ? "system-run" : command
->pixmap
));
228 child
->setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsEnabled
);
232 connect(treeWidget
, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
234 treeWidget
->setContextMenuPolicy(Qt::CustomContextMenu
);
235 connect(treeWidget
, SIGNAL(customContextMenuRequested(const QPoint
&)), SLOT(slotContextMenu(const QPoint
&)));
237 connect(treeWidget
, SIGNAL(itemChanged(QTreeWidgetItem
*, int)), SLOT(slotItemChanged(QTreeWidgetItem
*, int)));
239 treeWidget
->setSortingEnabled(false);
241 cbUseGUIRegExpEditor
= new QCheckBox(i18n("&Use graphical editor for editing regular expressions" ), this);
242 if ( /*KServiceTypeTrader::self()->query("KRegExpEditor/KRegExpEditor").isEmpty()*/ true) // see notice above about KRegExpEditor
244 cbUseGUIRegExpEditor
->hide();
245 cbUseGUIRegExpEditor
->setChecked( false );
247 mainLayout
->addWidget(cbUseGUIRegExpEditor
);
249 QHBoxLayout
*buttonLayout
= new QHBoxLayout
;
250 mainLayout
->addLayout(buttonLayout
);
252 QPushButton
*button
= new QPushButton(KIcon("list-add"), i18n("&Add Action"), this);
253 connect(button
, SIGNAL(clicked()), SLOT(slotAddAction()));
254 buttonLayout
->addWidget(button
);
256 delActionButton
= new QPushButton(KIcon("list-remove"), i18n("&Delete Action"), this);
257 connect(delActionButton
, SIGNAL(clicked()), SLOT(slotDeleteAction()));
258 buttonLayout
->addWidget(delActionButton
);
260 buttonLayout
->addStretch();
262 QPushButton
*advanced
= new QPushButton(KIcon("configure"), i18n("Advanced..."), this);
263 connect(advanced
, SIGNAL(clicked()), SLOT(slotAdvanced()));
264 buttonLayout
->addWidget(advanced
);
266 QLabel
*label
= new QLabel(i18n("Click on a highlighted item's column to change it. \"%s\" in a "
267 "command will be replaced with the clipboard contents."), this);
268 label
->setWordWrap(true);
269 mainLayout
->addWidget(label
);
271 QLabel
*labelRegexp
= new QLabel(i18n("For more information about regular expressions, you could have a look at the "
272 "<a href=\"http://en.wikipedia.org/wiki/Regular_expression\">Wikipedia entry "
273 "about this topic</a>."), this);
274 labelRegexp
->setOpenExternalLinks(true);
275 labelRegexp
->setWordWrap(true);
276 mainLayout
->addWidget(labelRegexp
);
278 delActionButton
->setEnabled(treeWidget
->currentItem());
281 ActionWidget::~ActionWidget()
285 void ActionWidget::selectionChanged()
287 delActionButton
->setEnabled(!treeWidget
->selectedItems().isEmpty());
290 void ActionWidget::slotContextMenu(const QPoint
& pos
)
292 QTreeWidgetItem
*item
= treeWidget
->itemAt(pos
);
296 KMenu
*menu
= new KMenu
;
297 QAction
*addCmd
= menu
->addAction(KIcon("list-add"), i18n("Add Command"));
298 QAction
*rmCmd
= menu
->addAction(KIcon("list-remove"), i18n("Remove Command"));
299 if ( !item
->parent() ) {// no "command" item
300 rmCmd
->setEnabled( false );
301 item
->setExpanded ( true );
304 QAction
*executed
= menu
->exec(mapToGlobal(pos
));
305 if ( executed
== addCmd
) {
306 QTreeWidgetItem
*child
= new QTreeWidgetItem(item
->parent() ? item
->parent() : item
, QStringList()
307 << i18n("Double-click here to set the command to be executed")
308 << i18n("<new command>"));
309 child
->setIcon(0, KIcon("system-run"));
310 child
->setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsEnabled
);
312 else if ( executed
== rmCmd
)
318 void ActionWidget::slotItemChanged(QTreeWidgetItem
*item
, int column
)
320 if (!item
->parent() || column
!= 0)
322 ClipCommand
command( item
->text(0), item
->text(1) );
324 treeWidget
->blockSignals(true); // don't lead in infinite recursion...
325 item
->setIcon(0, KIcon(command
.pixmap
.isEmpty() ? "system-run" : command
.pixmap
));
326 treeWidget
->blockSignals(false);
329 void ActionWidget::slotAddAction()
331 QTreeWidgetItem
*item
= new QTreeWidgetItem(treeWidget
,
332 QStringList() << i18n("Double-click here to set the regexp")
333 << i18n("<new action>"));
334 item
->setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsEnabled
);
338 void ActionWidget::slotDeleteAction()
340 QTreeWidgetItem
*item
= treeWidget
->currentItem();
341 if ( item
&& item
->parent() )
342 item
= item
->parent();
347 ActionList
* ActionWidget::actionList()
349 ClipAction
*action
= 0;
350 ActionList
*list
= new ActionList
;
352 QTreeWidgetItemIterator
it(treeWidget
);
354 if (!(*it
)->parent()) {
356 list
->append(action
);
359 action
= new ClipAction((*it
)->text(0), (*it
)->text(1));
362 action
->addCommand((*it
)->text(0), (*it
)->text(1), true);
367 list
->append(action
);
372 void ActionWidget::slotAdvanced()
376 dlg
.setCaption( i18n("Advanced Settings") );
377 dlg
.setButtons( KDialog::Ok
| KDialog::Cancel
);
379 AdvancedWidget
*widget
= new AdvancedWidget(&dlg
);
380 widget
->setWMClasses( m_wmClasses
);
382 dlg
.setMainWidget(widget
);
384 if ( dlg
.exec() == KDialog::Accepted
) {
385 m_wmClasses
= widget
->wmClasses();
389 AdvancedWidget::AdvancedWidget( QWidget
*parent
)
392 QVBoxLayout
*mainLayout
= new QVBoxLayout(this);
394 editListBox
= new KEditListBox(i18n("D&isable Actions for Windows of Type WM_CLASS"), this);
396 editListBox
->setButtons(KEditListBox::Add
| KEditListBox::Remove
);
397 editListBox
->setCheckAtEntering(true);
399 editListBox
->setWhatsThis(i18n("<qt>This lets you specify windows in which Klipper should "
400 "not invoke \"actions\". Use<br /><br />"
401 "<center><b>xprop | grep WM_CLASS</b></center><br />"
402 "in a terminal to find out the WM_CLASS of a window. "
403 "Next, click on the window you want to examine. The "
404 "first string it outputs after the equal sign is the one "
405 "you need to enter here.</qt>"));
406 mainLayout
->addWidget(editListBox
);
408 editListBox
->setFocus();
411 AdvancedWidget::~AdvancedWidget()
415 void AdvancedWidget::setWMClasses( const QStringList
& items
)
417 editListBox
->setItems(items
);
420 #include "configdialog.moc"