2 // Copyright (C) 1998 Matthias Hoelzer <hoelzer@kde.org>
3 // Copyright (C) 2002 David Faure <faure@kde.org>
4 // Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the7 implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <kmessagebox.h>
24 #include <kapplication.h>
25 #include <kpassivepopup.h>
26 #include <krecentdocument.h>
27 #include <kcmdlineargs.h>
28 #include <kaboutdata.h>
29 #include <kfiledialog.h>
30 #include <kicondialog.h>
31 #include <kdirselectdialog.h>
32 #include <kcolordialog.h>
34 #include <QtCore/QTimer>
35 #include <QtGui/QDesktopWidget>
39 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
44 #include <QtGui/QFileDialog>
51 extern "C" { int XSetTransientForHint( Display
*, unsigned long, unsigned long ); }
54 // this class hooks into the eventloop and outputs the id
55 // of shown dialogs or makes the dialog transient for other winids.
56 // Will destroy itself on app exit.
57 class WinIdEmbedder
: public QObject
60 WinIdEmbedder(bool printID
, WId winId
):
61 QObject(kapp
), print(printID
), id(winId
)
64 kapp
->installEventFilter(this);
67 bool eventFilter(QObject
*o
, QEvent
*e
);
73 bool WinIdEmbedder::eventFilter(QObject
*o
, QEvent
*e
)
75 if (e
->type() == QEvent::Show
&& o
->isWidgetType()
76 && o
->inherits("KDialog"))
78 QWidget
*w
= static_cast<QWidget
*>(o
);
80 cout
<< "winId: " << w
->winId() << endl
;
83 XSetTransientForHint(w
->x11Info().display(), w
->winId(), id
);
85 deleteLater(); // WinIdEmbedder is not needed anymore after the first dialog was shown
88 return QObject::eventFilter(o
, e
);
91 static void outputStringList(const QStringList
&list
, bool separateOutput
)
93 if ( separateOutput
) {
94 for ( QStringList::ConstIterator it
= list
.begin(); it
!= list
.end(); ++it
) {
95 cout
<< (*it
).toLocal8Bit().data() << endl
;
98 for ( QStringList::ConstIterator it
= list
.begin(); it
!= list
.end(); ++it
) {
99 cout
<< (*it
).toLocal8Bit().data() << " ";
105 static int directCommand(KCmdLineArgs
*args
)
108 bool separateOutput
= false;
109 bool printWId
= args
->isSet("print-winid");
110 bool embed
= args
->isSet("embed");
111 QString defaultEntry
;
114 KCmdLineArgs
*qtargs
= KCmdLineArgs::parsedArgs("qt"); // --title is a qt option
115 if(qtargs
->isSet("title")) {
116 title
= qtargs
->getOption("title");
120 if (args
->isSet("separate-output"))
122 separateOutput
= true;
124 if (printWId
|| embed
)
129 long l
= QString(args
->getOption("embed")).toLong(&ok
);
133 (void)new WinIdEmbedder(printWId
, id
);
136 // --yesno and other message boxes
137 KMessageBox::DialogType type
= (KMessageBox::DialogType
) 0;
139 if (args
->isSet("yesno")) {
141 type
= KMessageBox::QuestionYesNo
;
143 else if (args
->isSet("yesnocancel")) {
144 option
= "yesnocancel";
145 type
= KMessageBox::QuestionYesNoCancel
;
147 else if (args
->isSet("warningyesno")) {
148 option
= "warningyesno";
149 type
= KMessageBox::WarningYesNo
;
151 else if (args
->isSet("warningcontinuecancel")) {
152 option
= "warningcontinuecancel";
153 type
= KMessageBox::WarningContinueCancel
;
155 else if (args
->isSet("warningyesnocancel")) {
156 option
= "warningyesnocancel";
157 type
= KMessageBox::WarningYesNoCancel
;
159 else if (args
->isSet("sorry")) {
161 type
= KMessageBox::Sorry
;
163 else if (args
->isSet("error")) {
165 type
= KMessageBox::Error
;
167 else if (args
->isSet("msgbox")) {
169 type
= KMessageBox::Information
;
172 if ( !option
.isEmpty() )
174 KConfig
* dontagaincfg
= NULL
;
176 QString dontagain
; // QString()
177 if (args
->isSet("dontagain"))
179 QString value
= args
->getOption("dontagain");
180 QStringList values
= value
.split( ':', QString::SkipEmptyParts
);
181 if( values
.count() == 2 )
183 dontagaincfg
= new KConfig( values
[ 0 ] );
184 KMessageBox::setDontShowAskAgainConfig( dontagaincfg
);
185 dontagain
= values
[ 1 ];
188 qDebug( "Incorrect --dontagain!" );
192 QString text
= args
->getOption( option
);
194 while ((pos
= text
.indexOf( QLatin1String("\\n") )) >= 0)
196 text
.replace(pos
, 2, QLatin1String("\n"));
199 if ( type
== KMessageBox::WarningContinueCancel
) {
200 /* TODO configurable button texts*/
201 ret
= KMessageBox::messageBox( 0, type
, text
, title
, KStandardGuiItem::cont(),
202 KStandardGuiItem::no(), KStandardGuiItem::cancel(), dontagain
);
204 ret
= KMessageBox::messageBox( 0, type
, text
, title
/*, TODO configurable button texts*/,
205 KStandardGuiItem::yes(), KStandardGuiItem::no(), KStandardGuiItem::cancel(), dontagain
);
208 // ret is 1 for Ok, 2 for Cancel, 3 for Yes, 4 for No and 5 for Continue.
209 // We want to return 0 for ok, yes and continue, 1 for no and 2 for cancel
210 return (ret
== KMessageBox::Ok
|| ret
== KMessageBox::Yes
|| ret
== KMessageBox::Continue
) ? 0
211 : ( ret
== KMessageBox::No
? 1 : 2 );
214 // --inputbox text [init]
215 if (args
->isSet("inputbox"))
220 if (args
->count() > 0)
223 bool retcode
= Widgets::inputBox(0, title
, args
->getOption("inputbox"), init
, result
);
224 cout
<< result
.toLocal8Bit().data() << endl
;
225 return retcode
? 0 : 1;
230 if (args
->isSet("password"))
233 bool retcode
= Widgets::passwordBox(0, title
, args
->getOption("password"), result
);
234 cout
<< qPrintable(result
) << endl
;
235 return retcode
? 0 : 1;
239 if (args
->isSet("passivepopup"))
242 if (args
->count() > 0)
243 duration
= 1000 * args
->arg(0).toInt();
246 KPassivePopup
*popup
= KPassivePopup::message( KPassivePopup::Boxed
, // style
248 args
->getOption("passivepopup"),
249 QPixmap() /* do not crash 0*/, // icon
250 (QWidget
*)0UL, // parent
252 KDialog::centerOnScreen( popup
);
253 QTimer
*timer
= new QTimer();
254 QObject::connect( timer
, SIGNAL( timeout() ), kapp
, SLOT( quit() ) );
255 QObject::connect( popup
, SIGNAL( clicked() ), kapp
, SLOT( quit() ) );
256 timer
->setSingleShot( true );
257 timer
->start( duration
);
261 KCmdLineArgs
*args
= KCmdLineArgs::parsedArgs("kde");
262 if (args
&& args
->isSet("geometry"))
263 geometry
= args
->getOption("geometry");
264 if ( !geometry
.isEmpty()) {
267 int m
= XParseGeometry( geometry
.toLatin1(), &x
, &y
, (unsigned int*)&w
, (unsigned int*)&h
);
268 if ( (m
& XNegative
) )
269 x
= KApplication::desktop()->width() + x
- w
;
270 if ( (m
& YNegative
) )
271 y
= KApplication::desktop()->height() + y
- h
;
272 popup
->setAnchor( QPoint(x
, y
) );
279 // --textbox file [width] [height]
280 if (args
->isSet("textbox"))
285 if (args
->count() == 2) {
286 w
= args
->arg(0).toInt();
287 h
= args
->arg(1).toInt();
290 return Widgets::textBox(0, w
, h
, title
, args
->getOption("textbox"));
293 // --textinputbox file [width] [height]
294 if (args
->isSet("textinputbox"))
299 if (args
->count() == 4) {
300 w
= args
->arg(2).toInt();
301 h
= args
->arg(3).toInt();
305 list
.append(args
->getOption("textinputbox"));
307 if (args
->count() >= 1) {
308 for (int i
= 0; i
< args
->count(); i
++)
309 list
.append(args
->arg(i
));
313 int ret
= Widgets::textInputBox(0, w
, h
, title
, list
, result
);
314 cout
<< qPrintable(result
) << endl
;
318 // --combobox <text> [tag item] [tag item] ..."
319 if (args
->isSet("combobox")) {
321 if (args
->count() >= 2) {
322 for (int i
= 0; i
< args
->count(); i
++) {
323 list
.append(args
->arg(i
));
325 QString text
= args
->getOption("combobox");
326 if (args
->isSet("default")) {
327 defaultEntry
= args
->getOption("default");
330 bool retcode
= Widgets::comboBox(0, title
, text
, list
, defaultEntry
, result
);
331 cout
<< result
.toLocal8Bit().data() << endl
;
332 return retcode
? 0 : 1;
337 // --menu text [tag item] [tag item] ...
338 if (args
->isSet("menu")) {
340 if (args
->count() >= 2) {
341 for (int i
= 0; i
< args
->count(); i
++) {
342 list
.append(args
->arg(i
));
344 QString text
= args
->getOption("menu");
345 if (args
->isSet("default")) {
346 defaultEntry
= args
->getOption("default");
349 bool retcode
= Widgets::listBox(0, title
, text
, list
, defaultEntry
, result
);
350 if (1 == retcode
) { // OK was selected
351 cout
<< result
.toLocal8Bit().data() << endl
;
353 return retcode
? 0 : 1;
358 // --checklist text [tag item status] [tag item status] ...
359 if (args
->isSet("checklist")) {
361 if (args
->count() >= 3) {
362 for (int i
= 0; i
< args
->count(); i
++) {
363 list
.append(args
->arg(i
));
366 QString text
= args
->getOption("checklist");
369 bool retcode
= Widgets::checkList(0, title
, text
, list
, separateOutput
, result
);
371 for (int i
=0; i
<result
.count(); i
++)
372 if (!result
.at(i
).toLocal8Bit().isEmpty()) {
373 cout
<< result
.at(i
).toLocal8Bit().data() << endl
;
375 exit( retcode
? 0 : 1 );
380 // --radiolist text width height menuheight [tag item status]
381 if (args
->isSet("radiolist")) {
383 if (args
->count() >= 3) {
384 for (int i
= 0; i
< args
->count(); i
++) {
385 list
.append(args
->arg(i
));
388 QString text
= args
->getOption("radiolist");
390 bool retcode
= Widgets::radioBox(0, title
, text
, list
, result
);
391 cout
<< result
.toLocal8Bit().data() << endl
;
392 exit( retcode
? 0 : 1 );
397 // getopenfilename [startDir] [filter]
398 if (args
->isSet("getopenfilename")) {
401 startDir
= args
->getOption("getopenfilename");
402 if (args
->count() >= 1) {
403 filter
= args
->arg(0);
405 KFileDialog
dlg( startDir
, filter
, 0 );
406 dlg
.setOperationMode( KFileDialog::Opening
);
408 if (args
->isSet("multiple")) {
409 dlg
.setMode(KFile::Files
| KFile::LocalOnly
);
411 dlg
.setMode(KFile::File
| KFile::LocalOnly
);
413 Widgets::handleXGeometry(&dlg
);
414 kapp
->setTopWidget( &dlg
);
415 dlg
.setCaption(title
.isNull() ? i18n("Open") : title
);
418 if (args
->isSet("multiple")) {
419 QStringList result
= dlg
.selectedFiles();
420 if ( !result
.isEmpty() ) {
421 outputStringList( result
, separateOutput
);
425 QString result
= dlg
.selectedFile();
426 if (!result
.isEmpty()) {
427 cout
<< result
.toLocal8Bit().data() << endl
;
431 return 1; // canceled
435 // getsaveurl [startDir] [filter]
436 // getsavefilename [startDir] [filter]
437 if ( (args
->isSet("getsavefilename") ) || (args
->isSet("getsaveurl") ) ) {
440 if ( args
->isSet("getsavefilename") ) {
441 startDir
= args
->getOption("getsavefilename");
443 startDir
= args
->getOption("getsaveurl");
445 if (args
->count() >= 1) {
446 filter
= args
->arg(0);
448 // copied from KFileDialog::getSaveFileName(), so we can add geometry
449 bool specialDir
= ( startDir
.at(0) == ':' );
450 KFileDialog
dlg( specialDir
? startDir
: QString(), filter
, 0 );
452 dlg
.setSelection( startDir
);
453 dlg
.setOperationMode( KFileDialog::Saving
);
454 Widgets::handleXGeometry(&dlg
);
455 kapp
->setTopWidget( &dlg
);
456 dlg
.setCaption(title
.isNull() ? i18n("Save As") : title
);
459 if ( args
->isSet("getsaveurl") ) {
460 KUrl result
= dlg
.selectedUrl();
461 if ( result
.isValid()) {
463 cout
<< result
.url().toLocal8Bit().data() << endl
;
466 } else { // getsavefilename
467 QString result
= dlg
.selectedFile();
468 if (!result
.isEmpty()) {
469 KRecentDocument::add(result
);
470 cout
<< result
.toLocal8Bit().data() << endl
;
474 return 1; // canceled
477 // getexistingdirectory [startDir]
478 if (args
->isSet("getexistingdirectory")) {
480 startDir
= args
->getOption("getexistingdirectory");
483 result
= QFileDialog::getExistingDirectory( 0, title
, startDir
,
484 QFileDialog::DontResolveSymlinks
|
485 QFileDialog::ShowDirsOnly
);
488 KDirSelectDialog
myDialog( startDir
, true, 0 );
490 kapp
->setTopWidget( &myDialog
);
492 Widgets::handleXGeometry(&myDialog
);
493 if ( !title
.isNull() )
494 myDialog
.setCaption( title
);
496 if ( myDialog
.exec() == QDialog::Accepted
)
497 url
= myDialog
.url();
502 if (!result
.isEmpty()) {
503 cout
<< result
.toLocal8Bit().data() << endl
;
506 return 1; // canceled
509 // getopenurl [startDir] [filter]
510 if (args
->isSet("getopenurl")) {
513 startDir
= args
->getOption("getopenurl");
514 if (args
->count() >= 1) {
515 filter
= args
->arg(0);
517 KFileDialog
dlg( startDir
, filter
, 0 );
518 dlg
.setOperationMode( KFileDialog::Opening
);
520 if (args
->isSet("multiple")) {
521 dlg
.setMode(KFile::Files
);
523 dlg
.setMode(KFile::File
);
525 Widgets::handleXGeometry(&dlg
);
526 kapp
->setTopWidget( &dlg
);
527 dlg
.setCaption(title
.isNull() ? i18n("Open") : title
);
530 if (args
->isSet("multiple")) {
531 KUrl::List result
= dlg
.selectedUrls();
532 if ( !result
.isEmpty() ) {
533 outputStringList( result
.toStringList(), separateOutput
);
537 KUrl result
= dlg
.selectedUrl();
538 if (!result
.isEmpty()) {
539 cout
<< result
.url().toLocal8Bit().data() << endl
;
543 return 1; // canceled
546 // geticon [group] [context]
547 if (args
->isSet("geticon")) {
548 QString groupStr
, contextStr
;
549 groupStr
= args
->getOption("geticon");
550 if (args
->count() >= 1) {
551 contextStr
= args
->arg(0);
553 KIconLoader::Group group
= KIconLoader::NoGroup
;
554 if ( groupStr
== QLatin1String( "Desktop" ) )
555 group
= KIconLoader::Desktop
;
556 else if ( groupStr
== QLatin1String( "Toolbar" ) )
557 group
= KIconLoader::Toolbar
;
558 else if ( groupStr
== QLatin1String( "MainToolbar" ) )
559 group
= KIconLoader::MainToolbar
;
560 else if ( groupStr
== QLatin1String( "Small" ) )
561 group
= KIconLoader::Small
;
562 else if ( groupStr
== QLatin1String( "Panel" ) )
563 group
= KIconLoader::Panel
;
564 else if ( groupStr
== QLatin1String( "User" ) )
565 group
= KIconLoader::User
;
566 KIconLoader::Context context
= KIconLoader::Any
;
567 // From kicontheme.cpp
568 if ( contextStr
== QLatin1String( "Devices" ) )
569 context
= KIconLoader::Device
;
570 else if ( contextStr
== QLatin1String( "MimeTypes" ) )
571 context
= KIconLoader::MimeType
;
572 else if ( contextStr
== QLatin1String( "FileSystems" ) )
573 context
= KIconLoader::FileSystem
;
574 else if ( contextStr
== QLatin1String( "Applications" ) )
575 context
= KIconLoader::Application
;
576 else if ( contextStr
== QLatin1String( "Actions" ) )
577 context
= KIconLoader::Action
;
579 KIconDialog
dlg((QWidget
*)0L);
580 kapp
->setTopWidget( &dlg
);
581 dlg
.setup( group
, context
);
583 dlg
.setCaption(title
);
584 Widgets::handleXGeometry(&dlg
);
586 QString result
= dlg
.openDialog();
588 if (!result
.isEmpty()) {
589 cout
<< result
.toLocal8Bit().data() << endl
;
592 return 1; // canceled
595 // --progressbar text totalsteps
596 if (args
->isSet("progressbar"))
598 cout
<< "org.kde.kdialog-" << getpid() << " /ProgressDialog" << endl
;
603 int totalsteps
= 100;
604 QString text
= args
->getOption("progressbar");
606 if (args
->count() == 1)
607 totalsteps
= args
->arg(0).toInt();
609 return Widgets::progressBar(0, title
, text
, totalsteps
) ? 1 : 0;
613 if (args
->isSet("getcolor")) {
614 KColorDialog
dlg((QWidget
*)0L, true);
616 if (args
->isSet("default")) {
617 defaultEntry
= args
->getOption("default");
618 dlg
.setColor(defaultEntry
);
620 Widgets::handleXGeometry(&dlg
);
621 kapp
->setTopWidget(&dlg
);
622 dlg
.setCaption(title
.isNull() ? i18n("Choose Color") : title
);
624 if (dlg
.exec() == KColorDialog::Accepted
) {
626 if (dlg
.color().isValid()) {
627 result
= dlg
.color().name();
629 result
= dlg
.defaultColor().name();
631 cout
<< result
.toLocal8Bit().data() << endl
;
634 return 1; // cancelled
637 KCmdLineArgs::usage();
638 return -2; // NOTREACHED
642 int main(int argc
, char *argv
[])
644 KAboutData
aboutData( "kdialog", 0, ki18n("KDialog"),
645 "1.0", ki18n( "KDialog can be used to show nice dialog boxes from shell scripts" ),
646 KAboutData::License_GPL
,
647 ki18n("(C) 2000, Nick Thompson"));
648 aboutData
.addAuthor(ki18n("David Faure"), ki18n("Current maintainer"),"faure@kde.org");
649 aboutData
.addAuthor(ki18n("Brad Hards"), KLocalizedString(), "bradh@frogmouth.net");
650 aboutData
.addAuthor(ki18n("Nick Thompson"),KLocalizedString(), 0/*"nickthompson@lucent.com" bounces*/);
651 aboutData
.addAuthor(ki18n("Matthias Hölzer"),KLocalizedString(),"hoelzer@kde.org");
652 aboutData
.addAuthor(ki18n("David Gümbel"),KLocalizedString(),"david.guembel@gmx.net");
653 aboutData
.addAuthor(ki18n("Richard Moore"),KLocalizedString(),"rich@kde.org");
654 aboutData
.addAuthor(ki18n("Dawit Alemayehu"),KLocalizedString(),"adawit@kde.org");
656 KCmdLineArgs::init(argc
, argv
, &aboutData
);
658 KCmdLineOptions options
;
659 options
.add("yesno <text>", ki18n("Question message box with yes/no buttons"));
660 options
.add("yesnocancel <text>", ki18n("Question message box with yes/no/cancel buttons"));
661 options
.add("warningyesno <text>", ki18n("Warning message box with yes/no buttons"));
662 options
.add("warningcontinuecancel <text>", ki18n("Warning message box with continue/cancel buttons"));
663 options
.add("warningyesnocancel <text>", ki18n("Warning message box with yes/no/cancel buttons"));
664 options
.add("sorry <text>", ki18n("'Sorry' message box"));
665 options
.add("error <text>", ki18n("'Error' message box"));
666 options
.add("msgbox <text>", ki18n("Message Box dialog"));
667 options
.add("inputbox <text> <init>", ki18n("Input Box dialog"));
668 options
.add("password <text>", ki18n("Password dialog"));
669 options
.add("textbox <file> [width] [height]", ki18n("Text Box dialog"));
670 options
.add("textinputbox <text> <init> [width] [height]", ki18n("Text Input Box dialog"));
671 options
.add("combobox <text> [tag item] [tag item] ...", ki18n("ComboBox dialog"));
672 options
.add("menu <text> [tag item] [tag item] ...", ki18n("Menu dialog"));
673 options
.add("checklist <text> [tag item status] ...", ki18n("Check List dialog"));
674 options
.add("radiolist <text> [tag item status] ...", ki18n("Radio List dialog"));
675 options
.add("passivepopup <text> <timeout>", ki18n("Passive Popup"));
676 options
.add("getopenfilename [startDir] [filter]", ki18n("File dialog to open an existing file"));
677 options
.add("getsavefilename [startDir] [filter]", ki18n("File dialog to save a file"));
678 options
.add("getexistingdirectory [startDir]", ki18n("File dialog to select an existing directory"));
679 options
.add("getopenurl [startDir] [filter]", ki18n("File dialog to open an existing URL"));
680 options
.add("getsaveurl [startDir] [filter]", ki18n("File dialog to save a URL"));
681 options
.add("geticon [group] [context]", ki18n("Icon chooser dialog"));
682 options
.add("progressbar <text> [totalsteps]", ki18n("Progress bar dialog, returns a D-Bus reference for communication"));
683 options
.add("getcolor", ki18n("Color dialog to select a color"));
684 // TODO gauge stuff, reading values from stdin
685 options
.add("title <text>", ki18n("Dialog title"));
686 options
.add("default <text>", ki18n("Default entry to use for combobox, menu and color"));
687 options
.add("multiple", ki18n("Allows the --getopenurl and --getopenfilename options to return multiple files"));
688 options
.add("separate-output", ki18n("Return list items on separate lines (for checklist option and file open with --multiple)"));
689 options
.add("print-winid", ki18n("Outputs the winId of each dialog"));
690 options
.add("embed <winid>", ki18n("Makes the dialog transient for an X app specified by winid"));
691 options
.add("dontagain <file:entry>", ki18n("Config file and option name for saving the \"don't-show/ask-again\" state"));
692 options
.add("+[arg]", ki18n("Arguments - depending on main option"));
693 KCmdLineArgs::addCmdLineOptions( options
); // Add our own options.
697 QApplication::setWindowIcon(KIcon("system-run"));
699 KCmdLineArgs
*args
= KCmdLineArgs::parsedArgs();
701 // execute direct kdialog command
702 return directCommand(args
);