1/*
2 * Copyright (C) 2000 Matthias Elter <elter@kde.org>
3 * Copyright (C) 2008 Laurent Montel <montel@kde.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20
21#include "basictab.h"
22
23#include <QCheckBox>
24#include <QLabel>
25#include <QGroupBox>
26#include <QVBoxLayout>
27#include <QGridLayout>
28
29#include <KLocale>
30#include <KGlobal>
31#include <KDialog>
32#include <KKeySequenceWidget>
33#include <KLineEdit>
34#include <KIconButton>
35#include <KDesktopFile>
36#include <KUrlRequester>
37#include <KShell>
38
39#ifndef Q_WS_WIN
40#include "khotkeys.h"
41#endif
42
43#include "klinespellchecking.h"
44#include "menuinfo.h"
45
46#include "basictab.moc"
47
48BasicTab::BasicTab( QWidget *parent )
49 : KTabWidget(parent)
50{
51 _menuFolderInfo = 0;
52 _menuEntryInfo = 0;
53
54 // general group
55 QWidget *general_group = new QWidget();
56 QGridLayout *grid = new QGridLayout(general_group);
57 grid->setMargin( KDialog::marginHint() );
58 grid->setSpacing( KDialog::spacingHint() );
59
60 general_group->setAcceptDrops(false);
61
62 // setup line inputs
63 _nameEdit = new KLineEdit(general_group);
64 _nameEdit->setAcceptDrops(false);
65 _descriptionEdit = new KLineSpellChecking(general_group);
66 _descriptionEdit->setAcceptDrops(false);
67 _commentEdit = new KLineSpellChecking(general_group);
68 _commentEdit->setAcceptDrops(false);
69 _execEdit = new KUrlRequester(general_group);
70 _execEdit->lineEdit()->setAcceptDrops(false);
71 _execEdit->setWhatsThis(i18n(
72 "Following the command, you can have several place holders which will be replaced "
73 "with the actual values when the actual program is run:\n"
74 "%f - a single file name\n"
75 "%F - a list of files; use for applications that can open several local files at once\n"
76 "%u - a single URL\n"
77 "%U - a list of URLs\n"
78 "%d - the folder of the file to open\n"
79 "%D - a list of folders\n"
80 "%i - the icon\n"
81 "%m - the mini-icon\n"
82 "%c - the caption"));
83
84 _launchCB = new QCheckBox(i18n("Enable &launch feedback"), general_group);
85 _systrayCB = new QCheckBox(i18n("&Place in system tray"), general_group);
86 _onlyShowInKdeCB = new QCheckBox( i18n( "Only show in KDE" ), general_group );
87 _hiddenEntryCB = new QCheckBox( i18n( "Hidden entry" ), general_group );
88 _hiddenEntryCB->hide();
89
90 // setup labels
91 _nameLabel = new QLabel(i18n("&Name:"),general_group);
92 _nameLabel->setBuddy(_nameEdit);
93 _descriptionLabel = new QLabel(i18n("&Description:"),general_group);
94 _descriptionLabel->setBuddy(_descriptionEdit);
95 _commentLabel = new QLabel(i18n("&Comment:"),general_group);
96 _commentLabel->setBuddy(_commentEdit);
97 _execLabel = new QLabel(i18n("Co&mmand:"),general_group);
98 _execLabel->setBuddy(_execEdit);
99 grid->addWidget(_nameLabel, 0, 0);
100 grid->addWidget(_descriptionLabel, 1, 0);
101 grid->addWidget(_commentLabel, 2, 0);
102 grid->addWidget(_execLabel, 3, 0);
103
104 // connect line inputs
105 connect(_nameEdit, SIGNAL(textChanged(QString)),
106 SLOT(slotChanged()));
107 connect(_descriptionEdit, SIGNAL(textChanged(QString)),
108 SLOT(slotChanged()));
109 connect(_commentEdit, SIGNAL(textChanged(QString)),
110 SLOT(slotChanged()));
111 connect(_execEdit, SIGNAL(textChanged(QString)),
112 SLOT(slotChanged()));
113 connect(_execEdit, SIGNAL(urlSelected(KUrl)),
114 SLOT(slotExecSelected()));
115 connect(_launchCB, SIGNAL(clicked()), SLOT(launchcb_clicked()));
116 connect(_systrayCB, SIGNAL(clicked()), SLOT(systraycb_clicked()));
117 connect(_onlyShowInKdeCB, SIGNAL(clicked()), SLOT(onlyshowcb_clicked()) );
118 connect( _hiddenEntryCB, SIGNAL(clicked()), SLOT(hiddenentrycb_clicked()) );
119 // add line inputs to the grid
120 grid->addWidget(_nameEdit, 0, 1, 1, 1);
121 grid->addWidget(_descriptionEdit, 1, 1, 1, 1);
122 grid->addWidget(_commentEdit, 2, 1, 1, 2);
123 grid->addWidget(_execEdit, 3, 1, 1, 2);
124 grid->addWidget(_launchCB, 4, 0, 1, 3 );
125 grid->addWidget(_systrayCB, 5, 0, 1, 3 );
126 grid->addWidget(_onlyShowInKdeCB, 6, 0, 1, 3 );
127 grid->addWidget(_hiddenEntryCB, 7, 0, 1, 3 );
128
129 // setup icon button
130 _iconButton = new KIconButton(general_group);
131 _iconButton->setFixedSize(56,56);
132 _iconButton->setIconSize(32);
133 connect(_iconButton, SIGNAL(iconChanged(QString)), SLOT(slotChanged()));
134 grid->addWidget(_iconButton, 0, 2, 2, 1);
135 grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding), 8, 0, 1, 3);
136
137 // add the general group to the main layout
138 addTab(general_group, i18n("General"));
139
140 QWidget *advanced = new QWidget();
141 QVBoxLayout *advancedLayout = new QVBoxLayout(advanced);
142
143 // path group
144 _path_group = new QGroupBox(this);
145 QHBoxLayout *hboxLayout1 = new QHBoxLayout(_path_group);
146 hboxLayout1->setSpacing(KDialog::spacingHint());
147 hboxLayout1->setMargin(KDialog::marginHint());
148
149 _pathLabel = new QLabel(i18n("&Work path:"), _path_group);
150 hboxLayout1->addWidget(_pathLabel);
151 _pathEdit = new KUrlRequester(_path_group);
152 hboxLayout1->addWidget(_pathEdit);
153 _pathEdit->setMode(KFile::Directory | KFile::LocalOnly);
154 _pathEdit->lineEdit()->setAcceptDrops(false);
155
156 _pathLabel->setBuddy(_pathEdit);
157
158 connect(_pathEdit, SIGNAL(textChanged(QString)),
159 SLOT(slotChanged()));
160 advancedLayout->addWidget(_path_group);
161
162 // terminal group
163 _term_group = new QGroupBox(this);
164 QVBoxLayout *vbox = new QVBoxLayout(_term_group);
165 vbox->setMargin(KDialog::marginHint());
166 vbox->setSpacing(KDialog::spacingHint());
167
168 _terminalCB = new QCheckBox(i18n("Run in term&inal"), _term_group);
169 connect(_terminalCB, SIGNAL(clicked()), SLOT(termcb_clicked()));
170 vbox->addWidget(_terminalCB);
171
172 QWidget *hbox = new QWidget(_term_group);
173 QHBoxLayout *hboxLayout2 = new QHBoxLayout(hbox);
174 hbox->setLayout(hboxLayout2);
175 hboxLayout2->setSpacing(KDialog::spacingHint());
176 _termOptLabel = new QLabel(i18n("Terminal &options:"), hbox);
177 hboxLayout2->addWidget(_termOptLabel);
178 _termOptEdit = new KLineEdit(hbox);
179 hboxLayout2->addWidget(_termOptEdit);
180 _termOptEdit->setAcceptDrops(false);
181 _termOptLabel->setBuddy(_termOptEdit);
182
183 connect(_termOptEdit, SIGNAL(textChanged(QString)),
184 SLOT(slotChanged()));
185 vbox->addWidget(hbox);
186 advancedLayout->addWidget(_term_group);
187
188 _termOptEdit->setEnabled(false);
189
190 // uid group
191 _uid_group = new QGroupBox(this);
192 vbox = new QVBoxLayout(_uid_group);
193 vbox->setMargin(KDialog::marginHint());
194 vbox->setSpacing(KDialog::spacingHint());
195
196 _uidCB = new QCheckBox(i18n("&Run as a different user"), _uid_group);
197 connect(_uidCB, SIGNAL(clicked()), SLOT(uidcb_clicked()));
198 vbox->addWidget(_uidCB);
199
200 hbox = new QWidget(_uid_group);
201 QHBoxLayout *hboxLayout3 = new QHBoxLayout(hbox);
202 hbox->setLayout(hboxLayout3);
203 hboxLayout3->setSpacing(KDialog::spacingHint());
204 _uidLabel = new QLabel(i18n("&Username:"), hbox);
205 hboxLayout3->addWidget(_uidLabel);
206 _uidEdit = new KLineEdit(hbox);
207 hboxLayout3->addWidget(_uidEdit);
208 _uidEdit->setAcceptDrops(false);
209 _uidLabel->setBuddy(_uidEdit);
210
211 connect(_uidEdit, SIGNAL(textChanged(QString)),
212 SLOT(slotChanged()));
213 vbox->addWidget(hbox);
214 advancedLayout->addWidget(_uid_group);
215
216 _uidEdit->setEnabled(false);
217
218 // key binding group
219 general_group_keybind = new QGroupBox(this);
220 QHBoxLayout *keybindLayout = new QHBoxLayout(general_group_keybind);
221 keybindLayout->setMargin( KDialog::marginHint() );
222 keybindLayout->setSpacing( KDialog::spacingHint());
223
224 _keyEdit = new KKeySequenceWidget(general_group_keybind);
225 _keyEdit->setMultiKeyShortcutsAllowed(false);
226 QLabel *l = new QLabel( i18n("Current shortcut &key:"), general_group_keybind);
227 l->setBuddy( _keyEdit );
228 keybindLayout->addWidget(l);
229 connect( _keyEdit, SIGNAL(keySequenceChanged(QKeySequence)),
230 this, SLOT(slotCapturedKeySequence(QKeySequence)));
231 keybindLayout->addWidget(_keyEdit);
232 advancedLayout->addWidget( general_group_keybind );
233
234 advancedLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding));
235
236 addTab(advanced, i18n("Advanced"));
237#ifndef Q_WS_WIN
238 if (!KHotKeys::present())
239 general_group_keybind->hide();
240#endif
241 slotDisableAction();
242}
243
244void BasicTab::slotDisableAction()
245{
246 //disable all group at the beginning.
247 //because there is not file selected.
248 _nameEdit->setEnabled(false);
249 _descriptionEdit->setEnabled(false);
250 _commentEdit->setEnabled(false);
251 _execEdit->setEnabled(false);
252 _launchCB->setEnabled(false);
253 _systrayCB->setEnabled(false);
254 _onlyShowInKdeCB->setEnabled( false );
255 _hiddenEntryCB->setEnabled( false );
256 _nameLabel->setEnabled(false);
257 _descriptionLabel->setEnabled(false);
258 _commentLabel->setEnabled(false);
259 _execLabel->setEnabled(false);
260 _path_group->setEnabled(false);
261 _term_group->setEnabled(false);
262 _uid_group->setEnabled(false);
263 _iconButton->setEnabled(false);
264 // key binding part
265 general_group_keybind->setEnabled( false );
266}
267
268void BasicTab::enableWidgets(bool isDF, bool isDeleted)
269{
270 // set only basic attributes if it is not a .desktop file
271 _nameEdit->setEnabled(!isDeleted);
272 _descriptionEdit->setEnabled(!isDeleted);
273 _commentEdit->setEnabled(!isDeleted);
274 _iconButton->setEnabled(!isDeleted);
275 _execEdit->setEnabled(isDF && !isDeleted);
276 _launchCB->setEnabled(isDF && !isDeleted);
277 _systrayCB->setEnabled(isDF && !isDeleted);
278 _onlyShowInKdeCB->setEnabled( isDF && !isDeleted );
279 _hiddenEntryCB->setEnabled( isDF && !isDeleted );
280 _nameLabel->setEnabled(!isDeleted);
281 _descriptionLabel->setEnabled(!isDeleted);
282 _commentLabel->setEnabled(!isDeleted);
283 _execLabel->setEnabled(isDF && !isDeleted);
284
285 _path_group->setEnabled(isDF && !isDeleted);
286 _term_group->setEnabled(isDF && !isDeleted);
287 _uid_group->setEnabled(isDF && !isDeleted);
288 general_group_keybind->setEnabled( isDF && !isDeleted );
289
290 _termOptEdit->setEnabled(isDF && !isDeleted && _terminalCB->isChecked());
291 _termOptLabel->setEnabled(isDF && !isDeleted && _terminalCB->isChecked());
292
293 _uidEdit->setEnabled(isDF && !isDeleted && _uidCB->isChecked());
294 _uidLabel->setEnabled(isDF && !isDeleted && _uidCB->isChecked());
295}
296
297void BasicTab::setFolderInfo(MenuFolderInfo *folderInfo)
298{
299 blockSignals(true);
300 _menuFolderInfo = folderInfo;
301 _menuEntryInfo = 0;
302
303 _nameEdit->setText(folderInfo->caption);
304 _descriptionEdit->setText(folderInfo->genericname);
305 _descriptionEdit->setCursorPosition(0);
306 _commentEdit->setText(folderInfo->comment);
307 _commentEdit->setCursorPosition(0);
308 _iconButton->setIcon(folderInfo->icon);
309
310 // clean all disabled fields and return
311 _execEdit->lineEdit()->clear();
312 _pathEdit->lineEdit()->clear();
313 _termOptEdit->clear();
314 _uidEdit->clear();
315 _launchCB->setChecked(false);
316 _systrayCB->setChecked(false);
317 _terminalCB->setChecked(false);
318 _onlyShowInKdeCB->setChecked( false );
319 _hiddenEntryCB->setChecked( false );
320 _uidCB->setChecked(false);
321 _keyEdit->clearKeySequence();
322
323 enableWidgets(false, folderInfo->hidden);
324 blockSignals(false);
325}
326
327void BasicTab::setEntryInfo(MenuEntryInfo *entryInfo)
328{
329 blockSignals(true);
330 _menuFolderInfo = 0;
331 _menuEntryInfo = entryInfo;
332
333 if (!entryInfo)
334 {
335 _nameEdit->clear();
336 _descriptionEdit->clear();
337 _commentEdit->clear();
338 _iconButton->setIcon( QString() );
339
340 // key binding part
341 _keyEdit->clearKeySequence();
342
343 _execEdit->lineEdit()->clear();
344 _systrayCB->setChecked(false);
345 _onlyShowInKdeCB->setChecked( false );
346 _hiddenEntryCB->setChecked( false );
347
348 _pathEdit->lineEdit()->clear();
349 _termOptEdit->clear();
350 _uidEdit->clear();
351
352 _launchCB->setChecked(false);
353 _terminalCB->setChecked(false);
354 _uidCB->setChecked(false);
355 enableWidgets(true, true);
356 blockSignals(false);
357 return;
358 }
359
360 KDesktopFile *df = entryInfo->desktopFile();
361
362 _nameEdit->setText(df->readName());
363 _descriptionEdit->setText(df->readGenericName());
364 _descriptionEdit->setCursorPosition(0);
365 _commentEdit->setText(df->readComment());
366 _commentEdit->setCursorPosition(0);
367 _iconButton->setIcon(df->readIcon());
368
369 // key binding part
370#ifndef Q_WS_WIN
371 if( KHotKeys::present())
372 {
373 if ( !entryInfo->shortcut().isEmpty() )
374 _keyEdit->setKeySequence( entryInfo->shortcut().primary() );
375 else
376 _keyEdit->clearKeySequence();
377 }
378#endif
379 QString temp = df->desktopGroup().readEntry("Exec");
380 if (temp.startsWith(QLatin1String("ksystraycmd ")))
381 {
382 _execEdit->lineEdit()->setText(temp.right(temp.length()-12));
383 _systrayCB->setChecked(true);
384 }
385 else
386 {
387 _execEdit->lineEdit()->setText(temp);
388 _systrayCB->setChecked(false);
389 }
390
391 _pathEdit->lineEdit()->setText(df->readPath());
392 _termOptEdit->setText(df->desktopGroup().readEntry("TerminalOptions"));
393 _uidEdit->setText(df->desktopGroup().readEntry("X-KDE-Username"));
394
395 if( df->desktopGroup().hasKey( "StartupNotify" ))
396 _launchCB->setChecked(df->desktopGroup().readEntry("StartupNotify", true));
397 else // backwards comp.
398 _launchCB->setChecked(df->desktopGroup().readEntry("X-KDE-StartupNotify", true));
399
400 _onlyShowInKdeCB->setChecked( df->desktopGroup().readXdgListEntry("OnlyShowIn").contains( "KDE" ) ); // or maybe enable only if it contains nothing but KDE?
401
402 if ( df->desktopGroup().hasKey( "NoDisplay" ) )
403 _hiddenEntryCB->setChecked( df->desktopGroup().readEntry( "NoDisplay", true ) );
404 else
405 _hiddenEntryCB->setChecked( false );
406
407 if(df->desktopGroup().readEntry("Terminal", 0) == 1)
408 _terminalCB->setChecked(true);
409 else
410 _terminalCB->setChecked(false);
411
412 _uidCB->setChecked(df->desktopGroup().readEntry("X-KDE-SubstituteUID", false));
413
414 enableWidgets(true, entryInfo->hidden);
415 blockSignals(false);
416}
417
418void BasicTab::apply()
419{
420 if (_menuEntryInfo)
421 {
422 _menuEntryInfo->setDirty();
423 _menuEntryInfo->setCaption(_nameEdit->text());
424 _menuEntryInfo->setDescription(_descriptionEdit->text());
425 _menuEntryInfo->setIcon(_iconButton->icon());
426
427 KDesktopFile *df = _menuEntryInfo->desktopFile();
428 KConfigGroup dg = df->desktopGroup();
429 dg.writeEntry("Comment", _commentEdit->text());
430 if (_systrayCB->isChecked())
431 dg.writeEntry("Exec", _execEdit->lineEdit()->text().prepend("ksystraycmd "));
432 else
433 dg.writeEntry("Exec", _execEdit->lineEdit()->text());
434
435 dg.writePathEntry("Path", _pathEdit->lineEdit()->text());
436
437 if (_terminalCB->isChecked())
438 dg.writeEntry("Terminal", 1);
439 else
440 dg.writeEntry("Terminal", 0);
441
442 dg.writeEntry("TerminalOptions", _termOptEdit->text());
443 dg.writeEntry("X-KDE-SubstituteUID", _uidCB->isChecked());
444 dg.writeEntry("X-KDE-Username", _uidEdit->text());
445 dg.writeEntry("StartupNotify", _launchCB->isChecked());
446 dg.writeEntry( "NoDisplay", _hiddenEntryCB->isChecked() );
447
448 QStringList onlyShowIn = df->desktopGroup().readXdgListEntry("OnlyShowIn");
449 /* the exact semantics of this checkbox are unclear if there is more than just KDE in the list...
450 * For example: - The list is "Gnome;", the user enables "Only show in KDE" - should we remove Gnome?
451 * - The list is "Gnome;KDE;", the user unchecks the box - should we keep Gnome?
452 */
453 if ( _onlyShowInKdeCB->isChecked() && !onlyShowIn.contains("KDE"))
454 onlyShowIn << "KDE";
455 else if ( !_onlyShowInKdeCB->isChecked() && onlyShowIn.contains("KDE"))
456 onlyShowIn.removeAll("KDE");
457 if (onlyShowIn.isEmpty())
458 dg.deleteEntry("OnlyShowIn");
459 else
460 dg.writeXdgListEntry("OnlyShowIn", onlyShowIn);
461 }
462 else
463 {
464 _menuFolderInfo->setCaption(_nameEdit->text());
465 _menuFolderInfo->setGenericName(_descriptionEdit->text());
466 _menuFolderInfo->setComment(_commentEdit->text());
467 _menuFolderInfo->setIcon(_iconButton->icon());
468 }
469}
470
471void BasicTab::slotChanged()
472{
473 if (signalsBlocked())
474 return;
475 apply();
476 if (_menuEntryInfo)
477 emit changed( _menuEntryInfo );
478 else
479 emit changed( _menuFolderInfo );
480}
481
482void BasicTab::launchcb_clicked()
483{
484 slotChanged();
485}
486
487void BasicTab::systraycb_clicked()
488{
489 slotChanged();
490}
491
492void BasicTab::onlyshowcb_clicked()
493{
494 slotChanged();
495}
496
497void BasicTab::hiddenentrycb_clicked()
498{
499 slotChanged();
500}
501
502void BasicTab::termcb_clicked()
503{
504 _termOptEdit->setEnabled(_terminalCB->isChecked());
505 _termOptLabel->setEnabled(_terminalCB->isChecked());
506 slotChanged();
507}
508
509void BasicTab::uidcb_clicked()
510{
511 _uidEdit->setEnabled(_uidCB->isChecked());
512 _uidLabel->setEnabled(_uidCB->isChecked());
513 slotChanged();
514}
515
516void BasicTab::slotExecSelected()
517{
518 QString path = _execEdit->lineEdit()->text();
519 if (!path.startsWith('\''))
520 _execEdit->lineEdit()->setText(KShell::quoteArg(path));
521}
522
523void BasicTab::slotCapturedKeySequence(const QKeySequence& seq)
524{
525 if (signalsBlocked())
526 return;
527 KShortcut cut(seq, QKeySequence());
528#ifndef Q_WS_WIN
529 if (_menuEntryInfo->isShortcutAvailable( cut ) && KHotKeys::present() )
530 {
531 _menuEntryInfo->setShortcut( cut );
532 }
533 else
534 {
535 // We will not assign the shortcut so reset the visible key sequence
536 _keyEdit->setKeySequence(QKeySequence());
537 }
538#endif
539 if (_menuEntryInfo)
540 emit changed( _menuEntryInfo );
541}
542
543
544void BasicTab::updateHiddenEntry( bool show )
545{
546 if ( show )
547 _hiddenEntryCB->show();
548 else
549 _hiddenEntryCB->hide();
550}
551