kconfig: finer customization via popup menus
[linux-2.6.git] / scripts / kconfig / qconf.cc
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  */
5
6 #include <qapplication.h>
7 #include <qmainwindow.h>
8 #include <qtoolbar.h>
9 #include <qlayout.h>
10 #include <qvbox.h>
11 #include <qsplitter.h>
12 #include <qlistview.h>
13 #include <qtextbrowser.h>
14 #include <qlineedit.h>
15 #include <qlabel.h>
16 #include <qpushbutton.h>
17 #include <qmenubar.h>
18 #include <qmessagebox.h>
19 #include <qaction.h>
20 #include <qheader.h>
21 #include <qfiledialog.h>
22 #include <qdragobject.h>
23 #include <qregexp.h>
24
25 #include <stdlib.h>
26
27 #include "lkc.h"
28 #include "qconf.h"
29
30 #include "qconf.moc"
31 #include "images.c"
32
33 #ifdef _
34 # undef _
35 # define _ qgettext
36 #endif
37
38 static QApplication *configApp;
39 static ConfigSettings *configSettings;
40
41 static inline QString qgettext(const char* str)
42 {
43         return QString::fromLocal8Bit(gettext(str));
44 }
45
46 static inline QString qgettext(const QString& str)
47 {
48         return QString::fromLocal8Bit(gettext(str.latin1()));
49 }
50
51 /**
52  * Reads a list of integer values from the application settings.
53  */
54 QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
55 {
56         QValueList<int> result;
57         QStringList entryList = readListEntry(key, ok);
58         if (ok) {
59                 QStringList::Iterator it;
60                 for (it = entryList.begin(); it != entryList.end(); ++it)
61                         result.push_back((*it).toInt());
62         }
63
64         return result;
65 }
66
67 /**
68  * Writes a list of integer values to the application settings.
69  */
70 bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
71 {
72         QStringList stringList;
73         QValueList<int>::ConstIterator it;
74
75         for (it = value.begin(); it != value.end(); ++it)
76                 stringList.push_back(QString::number(*it));
77         return writeEntry(key, stringList);
78 }
79
80
81 #if QT_VERSION >= 300
82 /*
83  * set the new data
84  * TODO check the value
85  */
86 void ConfigItem::okRename(int col)
87 {
88         Parent::okRename(col);
89         sym_set_string_value(menu->sym, text(dataColIdx).latin1());
90 }
91 #endif
92
93 /*
94  * update the displayed of a menu entry
95  */
96 void ConfigItem::updateMenu(void)
97 {
98         ConfigList* list;
99         struct symbol* sym;
100         struct property *prop;
101         QString prompt;
102         int type;
103         tristate expr;
104
105         list = listView();
106         if (goParent) {
107                 setPixmap(promptColIdx, list->menuBackPix);
108                 prompt = "..";
109                 goto set_prompt;
110         }
111
112         sym = menu->sym;
113         prop = menu->prompt;
114         prompt = QString::fromLocal8Bit(menu_get_prompt(menu));
115
116         if (prop) switch (prop->type) {
117         case P_MENU:
118                 if (list->mode == singleMode || list->mode == symbolMode) {
119                         /* a menuconfig entry is displayed differently
120                          * depending whether it's at the view root or a child.
121                          */
122                         if (sym && list->rootEntry == menu)
123                                 break;
124                         setPixmap(promptColIdx, list->menuPix);
125                 } else {
126                         if (sym)
127                                 break;
128                         setPixmap(promptColIdx, 0);
129                 }
130                 goto set_prompt;
131         case P_COMMENT:
132                 setPixmap(promptColIdx, 0);
133                 goto set_prompt;
134         default:
135                 ;
136         }
137         if (!sym)
138                 goto set_prompt;
139
140         setText(nameColIdx, QString::fromLocal8Bit(sym->name));
141
142         type = sym_get_type(sym);
143         switch (type) {
144         case S_BOOLEAN:
145         case S_TRISTATE:
146                 char ch;
147
148                 if (!sym_is_changable(sym) && !list->showAll) {
149                         setPixmap(promptColIdx, 0);
150                         setText(noColIdx, QString::null);
151                         setText(modColIdx, QString::null);
152                         setText(yesColIdx, QString::null);
153                         break;
154                 }
155                 expr = sym_get_tristate_value(sym);
156                 switch (expr) {
157                 case yes:
158                         if (sym_is_choice_value(sym) && type == S_BOOLEAN)
159                                 setPixmap(promptColIdx, list->choiceYesPix);
160                         else
161                                 setPixmap(promptColIdx, list->symbolYesPix);
162                         setText(yesColIdx, "Y");
163                         ch = 'Y';
164                         break;
165                 case mod:
166                         setPixmap(promptColIdx, list->symbolModPix);
167                         setText(modColIdx, "M");
168                         ch = 'M';
169                         break;
170                 default:
171                         if (sym_is_choice_value(sym) && type == S_BOOLEAN)
172                                 setPixmap(promptColIdx, list->choiceNoPix);
173                         else
174                                 setPixmap(promptColIdx, list->symbolNoPix);
175                         setText(noColIdx, "N");
176                         ch = 'N';
177                         break;
178                 }
179                 if (expr != no)
180                         setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
181                 if (expr != mod)
182                         setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
183                 if (expr != yes)
184                         setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
185
186                 setText(dataColIdx, QChar(ch));
187                 break;
188         case S_INT:
189         case S_HEX:
190         case S_STRING:
191                 const char* data;
192
193                 data = sym_get_string_value(sym);
194
195 #if QT_VERSION >= 300
196                 int i = list->mapIdx(dataColIdx);
197                 if (i >= 0)
198                         setRenameEnabled(i, TRUE);
199 #endif
200                 setText(dataColIdx, data);
201                 if (type == S_STRING)
202                         prompt = QString("%1: %2").arg(prompt).arg(data);
203                 else
204                         prompt = QString("(%2) %1").arg(prompt).arg(data);
205                 break;
206         }
207         if (!sym_has_value(sym) && visible)
208                 prompt += " (NEW)";
209 set_prompt:
210         setText(promptColIdx, prompt);
211 }
212
213 void ConfigItem::testUpdateMenu(bool v)
214 {
215         ConfigItem* i;
216
217         visible = v;
218         if (!menu)
219                 return;
220
221         sym_calc_value(menu->sym);
222         if (menu->flags & MENU_CHANGED) {
223                 /* the menu entry changed, so update all list items */
224                 menu->flags &= ~MENU_CHANGED;
225                 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
226                         i->updateMenu();
227         } else if (listView()->updateAll)
228                 updateMenu();
229 }
230
231 void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
232 {
233         ConfigList* list = listView();
234
235         if (visible) {
236                 if (isSelected() && !list->hasFocus() && list->mode == menuMode)
237                         Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
238                 else
239                         Parent::paintCell(p, cg, column, width, align);
240         } else
241                 Parent::paintCell(p, list->disabledColorGroup, column, width, align);
242 }
243
244 /*
245  * construct a menu entry
246  */
247 void ConfigItem::init(void)
248 {
249         if (menu) {
250                 ConfigList* list = listView();
251                 nextItem = (ConfigItem*)menu->data;
252                 menu->data = this;
253
254                 if (list->mode != fullMode)
255                         setOpen(TRUE);
256                 sym_calc_value(menu->sym);
257         }
258         updateMenu();
259 }
260
261 /*
262  * destruct a menu entry
263  */
264 ConfigItem::~ConfigItem(void)
265 {
266         if (menu) {
267                 ConfigItem** ip = (ConfigItem**)&menu->data;
268                 for (; *ip; ip = &(*ip)->nextItem) {
269                         if (*ip == this) {
270                                 *ip = nextItem;
271                                 break;
272                         }
273                 }
274         }
275 }
276
277 ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
278         : Parent(parent)
279 {
280         connect(this, SIGNAL(lostFocus()), SLOT(hide()));
281 }
282
283 void ConfigLineEdit::show(ConfigItem* i)
284 {
285         item = i;
286         if (sym_get_string_value(item->menu->sym))
287                 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
288         else
289                 setText(QString::null);
290         Parent::show();
291         setFocus();
292 }
293
294 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
295 {
296         switch (e->key()) {
297         case Key_Escape:
298                 break;
299         case Key_Return:
300         case Key_Enter:
301                 sym_set_string_value(item->menu->sym, text().latin1());
302                 parent()->updateList(item);
303                 break;
304         default:
305                 Parent::keyPressEvent(e);
306                 return;
307         }
308         e->accept();
309         parent()->list->setFocus();
310         hide();
311 }
312
313 ConfigList::ConfigList(ConfigView* p, const char *name)
314         : Parent(p, name),
315           updateAll(false),
316           symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
317           choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
318           menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
319           showAll(false), showName(false), showRange(false), showData(false),
320           rootEntry(0), headerPopup(0)
321 {
322         int i;
323
324         setSorting(-1);
325         setRootIsDecorated(TRUE);
326         disabledColorGroup = palette().active();
327         disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
328         inactivedColorGroup = palette().active();
329         inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
330
331         connect(this, SIGNAL(selectionChanged(void)),
332                 SLOT(updateSelection(void)));
333
334         if (name) {
335                 configSettings->beginGroup(name);
336                 showAll = configSettings->readBoolEntry("/showAll", false);
337                 showName = configSettings->readBoolEntry("/showName", false);
338                 showRange = configSettings->readBoolEntry("/showRange", false);
339                 showData = configSettings->readBoolEntry("/showData", false);
340                 configSettings->endGroup();
341                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
342         }
343
344         for (i = 0; i < colNr; i++)
345                 colMap[i] = colRevMap[i] = -1;
346         addColumn(promptColIdx, "Option");
347
348         reinit();
349 }
350
351 void ConfigList::reinit(void)
352 {
353         removeColumn(dataColIdx);
354         removeColumn(yesColIdx);
355         removeColumn(modColIdx);
356         removeColumn(noColIdx);
357         removeColumn(nameColIdx);
358
359         if (showName)
360                 addColumn(nameColIdx, "Name");
361         if (showRange) {
362                 addColumn(noColIdx, "N");
363                 addColumn(modColIdx, "M");
364                 addColumn(yesColIdx, "Y");
365         }
366         if (showData)
367                 addColumn(dataColIdx, "Value");
368
369         updateListAll();
370 }
371
372 void ConfigList::saveSettings(void)
373 {
374         if (name()) {
375                 configSettings->beginGroup(name());
376                 configSettings->writeEntry("/showName", showName);
377                 configSettings->writeEntry("/showRange", showRange);
378                 configSettings->writeEntry("/showData", showData);
379                 configSettings->writeEntry("/showAll", showAll);
380                 configSettings->endGroup();
381         }
382 }
383
384 void ConfigList::updateSelection(void)
385 {
386         struct menu *menu;
387         enum prop_type type;
388
389         ConfigItem* item = (ConfigItem*)selectedItem();
390         if (!item)
391                 return;
392
393         menu = item->menu;
394         emit menuChanged(menu);
395         if (!menu)
396                 return;
397         type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
398         if (mode == menuMode && type == P_MENU)
399                 emit menuSelected(menu);
400 }
401
402 void ConfigList::updateList(ConfigItem* item)
403 {
404         ConfigItem* last = 0;
405
406         if (!rootEntry) {
407                 if (mode != listMode)
408                         goto update;
409                 QListViewItemIterator it(this);
410                 ConfigItem* item;
411
412                 for (; it.current(); ++it) {
413                         item = (ConfigItem*)it.current();
414                         if (!item->menu)
415                                 continue;
416                         item->testUpdateMenu(menu_is_visible(item->menu));
417                 }
418                 return;
419         }
420
421         if (rootEntry != &rootmenu && (mode == singleMode ||
422             (mode == symbolMode && rootEntry->parent != &rootmenu))) {
423                 item = firstChild();
424                 if (!item)
425                         item = new ConfigItem(this, 0, true);
426                 last = item;
427         }
428         if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
429             rootEntry->sym && rootEntry->prompt) {
430                 item = last ? last->nextSibling() : firstChild();
431                 if (!item)
432                         item = new ConfigItem(this, last, rootEntry, true);
433                 else
434                         item->testUpdateMenu(true);
435
436                 updateMenuList(item, rootEntry);
437                 triggerUpdate();
438                 return;
439         }
440 update:
441         updateMenuList(this, rootEntry);
442         triggerUpdate();
443 }
444
445 void ConfigList::setValue(ConfigItem* item, tristate val)
446 {
447         struct symbol* sym;
448         int type;
449         tristate oldval;
450
451         sym = item->menu ? item->menu->sym : 0;
452         if (!sym)
453                 return;
454
455         type = sym_get_type(sym);
456         switch (type) {
457         case S_BOOLEAN:
458         case S_TRISTATE:
459                 oldval = sym_get_tristate_value(sym);
460
461                 if (!sym_set_tristate_value(sym, val))
462                         return;
463                 if (oldval == no && item->menu->list)
464                         item->setOpen(TRUE);
465                 parent()->updateList(item);
466                 break;
467         }
468 }
469
470 void ConfigList::changeValue(ConfigItem* item)
471 {
472         struct symbol* sym;
473         struct menu* menu;
474         int type, oldexpr, newexpr;
475
476         menu = item->menu;
477         if (!menu)
478                 return;
479         sym = menu->sym;
480         if (!sym) {
481                 if (item->menu->list)
482                         item->setOpen(!item->isOpen());
483                 return;
484         }
485
486         type = sym_get_type(sym);
487         switch (type) {
488         case S_BOOLEAN:
489         case S_TRISTATE:
490                 oldexpr = sym_get_tristate_value(sym);
491                 newexpr = sym_toggle_tristate_value(sym);
492                 if (item->menu->list) {
493                         if (oldexpr == newexpr)
494                                 item->setOpen(!item->isOpen());
495                         else if (oldexpr == no)
496                                 item->setOpen(TRUE);
497                 }
498                 if (oldexpr != newexpr)
499                         parent()->updateList(item);
500                 break;
501         case S_INT:
502         case S_HEX:
503         case S_STRING:
504 #if QT_VERSION >= 300
505                 if (colMap[dataColIdx] >= 0)
506                         item->startRename(colMap[dataColIdx]);
507                 else
508 #endif
509                         parent()->lineEdit->show(item);
510                 break;
511         }
512 }
513
514 void ConfigList::setRootMenu(struct menu *menu)
515 {
516         enum prop_type type;
517
518         if (rootEntry == menu)
519                 return;
520         type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
521         if (type != P_MENU)
522                 return;
523         updateMenuList(this, 0);
524         rootEntry = menu;
525         updateListAll();
526         setSelected(currentItem(), hasFocus());
527 }
528
529 void ConfigList::setParentMenu(void)
530 {
531         ConfigItem* item;
532         struct menu *oldroot;
533
534         oldroot = rootEntry;
535         if (rootEntry == &rootmenu)
536                 return;
537         setRootMenu(menu_get_parent_menu(rootEntry->parent));
538
539         QListViewItemIterator it(this);
540         for (; (item = (ConfigItem*)it.current()); it++) {
541                 if (item->menu == oldroot) {
542                         setCurrentItem(item);
543                         ensureItemVisible(item);
544                         break;
545                 }
546         }
547 }
548
549 /*
550  * update all the children of a menu entry
551  *   removes/adds the entries from the parent widget as necessary
552  *
553  * parent: either the menu list widget or a menu entry widget
554  * menu: entry to be updated
555  */
556 template <class P>
557 void ConfigList::updateMenuList(P* parent, struct menu* menu)
558 {
559         struct menu* child;
560         ConfigItem* item;
561         ConfigItem* last;
562         bool visible;
563         enum prop_type type;
564
565         if (!menu) {
566                 while ((item = parent->firstChild()))
567                         delete item;
568                 return;
569         }
570
571         last = parent->firstChild();
572         if (last && !last->goParent)
573                 last = 0;
574         for (child = menu->list; child; child = child->next) {
575                 item = last ? last->nextSibling() : parent->firstChild();
576                 type = child->prompt ? child->prompt->type : P_UNKNOWN;
577
578                 switch (mode) {
579                 case menuMode:
580                         if (!(child->flags & MENU_ROOT))
581                                 goto hide;
582                         break;
583                 case symbolMode:
584                         if (child->flags & MENU_ROOT)
585                                 goto hide;
586                         break;
587                 default:
588                         break;
589                 }
590
591                 visible = menu_is_visible(child);
592                 if (showAll || visible) {
593                         if (!item || item->menu != child)
594                                 item = new ConfigItem(parent, last, child, visible);
595                         else
596                                 item->testUpdateMenu(visible);
597
598                         if (mode == fullMode || mode == menuMode || type != P_MENU)
599                                 updateMenuList(item, child);
600                         else
601                                 updateMenuList(item, 0);
602                         last = item;
603                         continue;
604                 }
605         hide:
606                 if (item && item->menu == child) {
607                         last = parent->firstChild();
608                         if (last == item)
609                                 last = 0;
610                         else while (last->nextSibling() != item)
611                                 last = last->nextSibling();
612                         delete item;
613                 }
614         }
615 }
616
617 void ConfigList::keyPressEvent(QKeyEvent* ev)
618 {
619         QListViewItem* i = currentItem();
620         ConfigItem* item;
621         struct menu *menu;
622         enum prop_type type;
623
624         if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
625                 emit parentSelected();
626                 ev->accept();
627                 return;
628         }
629
630         if (!i) {
631                 Parent::keyPressEvent(ev);
632                 return;
633         }
634         item = (ConfigItem*)i;
635
636         switch (ev->key()) {
637         case Key_Return:
638         case Key_Enter:
639                 if (item->goParent) {
640                         emit parentSelected();
641                         break;
642                 }
643                 menu = item->menu;
644                 if (!menu)
645                         break;
646                 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
647                 if (type == P_MENU && rootEntry != menu &&
648                     mode != fullMode && mode != menuMode) {
649                         emit menuSelected(menu);
650                         break;
651                 }
652         case Key_Space:
653                 changeValue(item);
654                 break;
655         case Key_N:
656                 setValue(item, no);
657                 break;
658         case Key_M:
659                 setValue(item, mod);
660                 break;
661         case Key_Y:
662                 setValue(item, yes);
663                 break;
664         default:
665                 Parent::keyPressEvent(ev);
666                 return;
667         }
668         ev->accept();
669 }
670
671 void ConfigList::contentsMousePressEvent(QMouseEvent* e)
672 {
673         //QPoint p(contentsToViewport(e->pos()));
674         //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
675         Parent::contentsMousePressEvent(e);
676 }
677
678 void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
679 {
680         QPoint p(contentsToViewport(e->pos()));
681         ConfigItem* item = (ConfigItem*)itemAt(p);
682         struct menu *menu;
683         enum prop_type ptype;
684         const QPixmap* pm;
685         int idx, x;
686
687         if (!item)
688                 goto skip;
689
690         menu = item->menu;
691         x = header()->offset() + p.x();
692         idx = colRevMap[header()->sectionAt(x)];
693         switch (idx) {
694         case promptColIdx:
695                 pm = item->pixmap(promptColIdx);
696                 if (pm) {
697                         int off = header()->sectionPos(0) + itemMargin() +
698                                 treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
699                         if (x >= off && x < off + pm->width()) {
700                                 if (item->goParent) {
701                                         emit parentSelected();
702                                         break;
703                                 } else if (!menu)
704                                         break;
705                                 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
706                                 if (ptype == P_MENU && rootEntry != menu &&
707                                     mode != fullMode && mode != menuMode)
708                                         emit menuSelected(menu);
709                                 else
710                                         changeValue(item);
711                         }
712                 }
713                 break;
714         case noColIdx:
715                 setValue(item, no);
716                 break;
717         case modColIdx:
718                 setValue(item, mod);
719                 break;
720         case yesColIdx:
721                 setValue(item, yes);
722                 break;
723         case dataColIdx:
724                 changeValue(item);
725                 break;
726         }
727
728 skip:
729         //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
730         Parent::contentsMouseReleaseEvent(e);
731 }
732
733 void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
734 {
735         //QPoint p(contentsToViewport(e->pos()));
736         //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
737         Parent::contentsMouseMoveEvent(e);
738 }
739
740 void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
741 {
742         QPoint p(contentsToViewport(e->pos()));
743         ConfigItem* item = (ConfigItem*)itemAt(p);
744         struct menu *menu;
745         enum prop_type ptype;
746
747         if (!item)
748                 goto skip;
749         if (item->goParent) {
750                 emit parentSelected();
751                 goto skip;
752         }
753         menu = item->menu;
754         if (!menu)
755                 goto skip;
756         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
757         if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
758                 emit menuSelected(menu);
759         else if (menu->sym)
760                 changeValue(item);
761
762 skip:
763         //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
764         Parent::contentsMouseDoubleClickEvent(e);
765 }
766
767 void ConfigList::focusInEvent(QFocusEvent *e)
768 {
769         Parent::focusInEvent(e);
770
771         QListViewItem* item = currentItem();
772         if (!item)
773                 return;
774
775         setSelected(item, TRUE);
776         emit gotFocus();
777 }
778
779 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
780 {
781         if (e->y() <= header()->geometry().bottom()) {
782                 if (!headerPopup) {
783                         QAction *action;
784
785                         headerPopup = new QPopupMenu(this);
786                         action = new QAction("Show Name", 0, this);
787                           action->setToggleAction(TRUE);
788                           connect(action, SIGNAL(toggled(bool)),
789                                   parent(), SLOT(setShowName(bool)));
790                           connect(parent(), SIGNAL(showNameChanged(bool)),
791                                   action, SLOT(setOn(bool)));
792                           action->setOn(showName);
793                           action->addTo(headerPopup);
794                         action = new QAction("Show Range", 0, this);
795                           action->setToggleAction(TRUE);
796                           connect(action, SIGNAL(toggled(bool)),
797                                   parent(), SLOT(setShowRange(bool)));
798                           connect(parent(), SIGNAL(showRangeChanged(bool)),
799                                   action, SLOT(setOn(bool)));
800                           action->setOn(showRange);
801                           action->addTo(headerPopup);
802                         action = new QAction("Show Data", 0, this);
803                           action->setToggleAction(TRUE);
804                           connect(action, SIGNAL(toggled(bool)),
805                                   parent(), SLOT(setShowData(bool)));
806                           connect(parent(), SIGNAL(showDataChanged(bool)),
807                                   action, SLOT(setOn(bool)));
808                           action->setOn(showData);
809                           action->addTo(headerPopup);
810                 }
811                 headerPopup->exec(e->globalPos());
812                 e->accept();
813         } else
814                 e->ignore();
815 }
816
817 ConfigView* ConfigView::viewList;
818
819 ConfigView::ConfigView(QWidget* parent, const char *name)
820         : Parent(parent, name)
821 {
822         list = new ConfigList(this, name);
823         lineEdit = new ConfigLineEdit(this);
824         lineEdit->hide();
825
826         this->nextView = viewList;
827         viewList = this;
828 }
829
830 ConfigView::~ConfigView(void)
831 {
832         ConfigView** vp;
833
834         for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
835                 if (*vp == this) {
836                         *vp = nextView;
837                         break;
838                 }
839         }
840 }
841
842 void ConfigView::setShowAll(bool b)
843 {
844         if (list->showAll != b) {
845                 list->showAll = b;
846                 list->updateListAll();
847                 emit showAllChanged(b);
848         }
849 }
850
851 void ConfigView::setShowName(bool b)
852 {
853         if (list->showName != b) {
854                 list->showName = b;
855                 list->reinit();
856                 emit showNameChanged(b);
857         }
858 }
859
860 void ConfigView::setShowRange(bool b)
861 {
862         if (list->showRange != b) {
863                 list->showRange = b;
864                 list->reinit();
865                 emit showRangeChanged(b);
866         }
867 }
868
869 void ConfigView::setShowData(bool b)
870 {
871         if (list->showData != b) {
872                 list->showData = b;
873                 list->reinit();
874                 emit showDataChanged(b);
875         }
876 }
877
878 void ConfigList::setAllOpen(bool open)
879 {
880         QListViewItemIterator it(this);
881
882         for (; it.current(); it++)
883                 it.current()->setOpen(open);
884 }
885
886 void ConfigView::updateList(ConfigItem* item)
887 {
888         ConfigView* v;
889
890         for (v = viewList; v; v = v->nextView)
891                 v->list->updateList(item);
892 }
893
894 void ConfigView::updateListAll(void)
895 {
896         ConfigView* v;
897
898         for (v = viewList; v; v = v->nextView)
899                 v->list->updateListAll();
900 }
901
902 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
903         : Parent(parent, name), menu(0)
904 {
905         if (name) {
906                 configSettings->beginGroup(name);
907                 _showDebug = configSettings->readBoolEntry("/showDebug", false);
908                 configSettings->endGroup();
909                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
910         }
911 }
912
913 void ConfigInfoView::saveSettings(void)
914 {
915         if (name()) {
916                 configSettings->beginGroup(name());
917                 configSettings->writeEntry("/showDebug", showDebug());
918                 configSettings->endGroup();
919         }
920 }
921
922 void ConfigInfoView::setShowDebug(bool b)
923 {
924         if (_showDebug != b) {
925                 _showDebug = b;
926                 if (menu)
927                         menuInfo();
928                 emit showDebugChanged(b);
929         }
930 }
931
932 void ConfigInfoView::setInfo(struct menu *m)
933 {
934         menu = m;
935         if (!menu)
936                 clear();
937         else
938                 menuInfo();
939 }
940
941 void ConfigInfoView::setSource(const QString& name)
942 {
943         const char *p = name.latin1();
944
945         menu = NULL;
946
947         switch (p[0]) {
948         case 'm':
949                 if (sscanf(p, "m%p", &menu) == 1)
950                         menuInfo();
951                 break;
952         }
953 }
954
955 void ConfigInfoView::menuInfo(void)
956 {
957         struct symbol* sym;
958         QString head, debug, help;
959
960         sym = menu->sym;
961         if (sym) {
962                 if (menu->prompt) {
963                         head += "<big><b>";
964                         head += print_filter(_(menu->prompt->text));
965                         head += "</b></big>";
966                         if (sym->name) {
967                                 head += " (";
968                                 head += print_filter(sym->name);
969                                 head += ")";
970                         }
971                 } else if (sym->name) {
972                         head += "<big><b>";
973                         head += print_filter(sym->name);
974                         head += "</b></big>";
975                 }
976                 head += "<br><br>";
977
978                 if (showDebug())
979                         debug = debug_info(sym);
980
981                 help = print_filter(_(sym->help));
982         } else if (menu->prompt) {
983                 head += "<big><b>";
984                 head += print_filter(_(menu->prompt->text));
985                 head += "</b></big><br><br>";
986                 if (showDebug()) {
987                         if (menu->prompt->visible.expr) {
988                                 debug += "&nbsp;&nbsp;dep: ";
989                                 expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
990                                 debug += "<br><br>";
991                         }
992                 }
993         }
994         if (showDebug())
995                 debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
996
997         setText(head + debug + help);
998 }
999
1000 QString ConfigInfoView::debug_info(struct symbol *sym)
1001 {
1002         QString debug;
1003
1004         debug += "type: ";
1005         debug += print_filter(sym_type_name(sym->type));
1006         if (sym_is_choice(sym))
1007                 debug += " (choice)";
1008         debug += "<br>";
1009         if (sym->rev_dep.expr) {
1010                 debug += "reverse dep: ";
1011                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1012                 debug += "<br>";
1013         }
1014         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1015                 switch (prop->type) {
1016                 case P_PROMPT:
1017                 case P_MENU:
1018                         debug += "prompt: ";
1019                         debug += print_filter(_(prop->text));
1020                         debug += "<br>";
1021                         break;
1022                 case P_DEFAULT:
1023                         debug += "default: ";
1024                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1025                         debug += "<br>";
1026                         break;
1027                 case P_CHOICE:
1028                         if (sym_is_choice(sym)) {
1029                                 debug += "choice: ";
1030                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1031                                 debug += "<br>";
1032                         }
1033                         break;
1034                 case P_SELECT:
1035                         debug += "select: ";
1036                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1037                         debug += "<br>";
1038                         break;
1039                 case P_RANGE:
1040                         debug += "range: ";
1041                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1042                         debug += "<br>";
1043                         break;
1044                 default:
1045                         debug += "unknown property: ";
1046                         debug += prop_get_type_name(prop->type);
1047                         debug += "<br>";
1048                 }
1049                 if (prop->visible.expr) {
1050                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1051                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1052                         debug += "<br>";
1053                 }
1054         }
1055         debug += "<br>";
1056
1057         return debug;
1058 }
1059
1060 QString ConfigInfoView::print_filter(const QString &str)
1061 {
1062         QRegExp re("[<>&\"\\n]");
1063         QString res = str;
1064         for (int i = 0; (i = res.find(re, i)) >= 0;) {
1065                 switch (res[i].latin1()) {
1066                 case '<':
1067                         res.replace(i, 1, "&lt;");
1068                         i += 4;
1069                         break;
1070                 case '>':
1071                         res.replace(i, 1, "&gt;");
1072                         i += 4;
1073                         break;
1074                 case '&':
1075                         res.replace(i, 1, "&amp;");
1076                         i += 5;
1077                         break;
1078                 case '"':
1079                         res.replace(i, 1, "&quot;");
1080                         i += 6;
1081                         break;
1082                 case '\n':
1083                         res.replace(i, 1, "<br>");
1084                         i += 4;
1085                         break;
1086                 }
1087         }
1088         return res;
1089 }
1090
1091 void ConfigInfoView::expr_print_help(void *data, const char *str)
1092 {
1093         reinterpret_cast<QString*>(data)->append(print_filter(str));
1094 }
1095
1096 QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
1097 {
1098         QPopupMenu* popup = Parent::createPopupMenu(pos);
1099         QAction* action = new QAction("Show Debug Info", 0, popup);
1100           action->setToggleAction(TRUE);
1101           connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1102           connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1103           action->setOn(showDebug());
1104         popup->insertSeparator();
1105         action->addTo(popup);
1106         return popup;
1107 }
1108
1109 void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
1110 {
1111         Parent::contentsContextMenuEvent(e);
1112 }
1113
1114 ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
1115         : Parent(parent, name), result(NULL)
1116 {
1117         setCaption("Search Config");
1118
1119         QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
1120         QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
1121         layout2->addWidget(new QLabel("Find:", this));
1122         editField = new QLineEdit(this);
1123         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1124         layout2->addWidget(editField);
1125         searchButton = new QPushButton("Search", this);
1126         searchButton->setAutoDefault(FALSE);
1127         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1128         layout2->addWidget(searchButton);
1129         layout1->addLayout(layout2);
1130
1131         split = new QSplitter(this);
1132         split->setOrientation(QSplitter::Vertical);
1133         list = new ConfigView(split, name);
1134         list->list->mode = listMode;
1135         info = new ConfigInfoView(split, name);
1136         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1137                 info, SLOT(setInfo(struct menu *)));
1138         layout1->addWidget(split);
1139
1140         if (name) {
1141                 int x, y, width, height;
1142                 bool ok;
1143
1144                 configSettings->beginGroup(name);
1145                 width = configSettings->readNumEntry("/window width", parent->width() / 2);
1146                 height = configSettings->readNumEntry("/window height", parent->height() / 2);
1147                 resize(width, height);
1148                 x = configSettings->readNumEntry("/window x", 0, &ok);
1149                 if (ok)
1150                         y = configSettings->readNumEntry("/window y", 0, &ok);
1151                 if (ok)
1152                         move(x, y);
1153                 QValueList<int> sizes = configSettings->readSizes("/split", &ok);
1154                 if (ok)
1155                         split->setSizes(sizes);
1156                 configSettings->endGroup();
1157                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1158         }
1159 }
1160
1161 void ConfigSearchWindow::saveSettings(void)
1162 {
1163         if (name()) {
1164                 configSettings->beginGroup(name());
1165                 configSettings->writeEntry("/window x", pos().x());
1166                 configSettings->writeEntry("/window y", pos().y());
1167                 configSettings->writeEntry("/window width", size().width());
1168                 configSettings->writeEntry("/window height", size().height());
1169                 configSettings->writeSizes("/split", split->sizes());
1170                 configSettings->endGroup();
1171         }
1172 }
1173
1174 void ConfigSearchWindow::search(void)
1175 {
1176         struct symbol **p;
1177         struct property *prop;
1178         ConfigItem *lastItem = NULL;
1179
1180         free(result);
1181         list->list->clear();
1182
1183         result = sym_re_search(editField->text().latin1());
1184         if (!result)
1185                 return;
1186         for (p = result; *p; p++) {
1187                 for_all_prompts((*p), prop)
1188                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1189                                                   menu_is_visible(prop->menu));
1190         }
1191 }
1192
1193 /*
1194  * Construct the complete config widget
1195  */
1196 ConfigMainWindow::ConfigMainWindow(void)
1197 {
1198         QMenuBar* menu;
1199         bool ok;
1200         int x, y, width, height;
1201
1202         QWidget *d = configApp->desktop();
1203
1204         width = configSettings->readNumEntry("/window width", d->width() - 64);
1205         height = configSettings->readNumEntry("/window height", d->height() - 64);
1206         resize(width, height);
1207         x = configSettings->readNumEntry("/window x", 0, &ok);
1208         if (ok)
1209                 y = configSettings->readNumEntry("/window y", 0, &ok);
1210         if (ok)
1211                 move(x, y);
1212
1213         split1 = new QSplitter(this);
1214         split1->setOrientation(QSplitter::Horizontal);
1215         setCentralWidget(split1);
1216
1217         menuView = new ConfigView(split1, "menu");
1218         menuList = menuView->list;
1219
1220         split2 = new QSplitter(split1);
1221         split2->setOrientation(QSplitter::Vertical);
1222
1223         // create config tree
1224         configView = new ConfigView(split2, "config");
1225         configList = configView->list;
1226
1227         helpText = new ConfigInfoView(split2, "help");
1228         helpText->setTextFormat(Qt::RichText);
1229
1230         setTabOrder(configList, helpText);
1231         configList->setFocus();
1232
1233         menu = menuBar();
1234         toolBar = new QToolBar("Tools", this);
1235
1236         backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
1237           connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1238           backAction->setEnabled(FALSE);
1239         QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
1240           connect(quitAction, SIGNAL(activated()), SLOT(close()));
1241         QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
1242           connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1243         QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
1244           connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1245         QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
1246           connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1247         QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
1248           connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1249         QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
1250           connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1251         QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
1252           connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1253         QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
1254           connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1255
1256         QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
1257           showNameAction->setToggleAction(TRUE);
1258           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1259           connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1260           showNameAction->setOn(configView->showName());
1261         QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
1262           showRangeAction->setToggleAction(TRUE);
1263           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1264           connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1265           showRangeAction->setOn(configList->showRange);
1266         QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
1267           showDataAction->setToggleAction(TRUE);
1268           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1269           connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1270           showDataAction->setOn(configList->showData);
1271         QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
1272           showAllAction->setToggleAction(TRUE);
1273           connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
1274           connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
1275           showAllAction->setOn(configList->showAll);
1276         QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
1277           showDebugAction->setToggleAction(TRUE);
1278           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1279           connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1280           showDebugAction->setOn(helpText->showDebug());
1281
1282         QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
1283           connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1284         QAction *showAboutAction = new QAction(NULL, "About", 0, this);
1285           connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1286
1287         // init tool bar
1288         backAction->addTo(toolBar);
1289         toolBar->addSeparator();
1290         loadAction->addTo(toolBar);
1291         saveAction->addTo(toolBar);
1292         toolBar->addSeparator();
1293         singleViewAction->addTo(toolBar);
1294         splitViewAction->addTo(toolBar);
1295         fullViewAction->addTo(toolBar);
1296
1297         // create config menu
1298         QPopupMenu* config = new QPopupMenu(this);
1299         menu->insertItem("&File", config);
1300         loadAction->addTo(config);
1301         saveAction->addTo(config);
1302         saveAsAction->addTo(config);
1303         config->insertSeparator();
1304         searchAction->addTo(config);
1305         config->insertSeparator();
1306         quitAction->addTo(config);
1307
1308         // create options menu
1309         QPopupMenu* optionMenu = new QPopupMenu(this);
1310         menu->insertItem("&Option", optionMenu);
1311         showNameAction->addTo(optionMenu);
1312         showRangeAction->addTo(optionMenu);
1313         showDataAction->addTo(optionMenu);
1314         optionMenu->insertSeparator();
1315         showAllAction->addTo(optionMenu);
1316         showDebugAction->addTo(optionMenu);
1317
1318         // create help menu
1319         QPopupMenu* helpMenu = new QPopupMenu(this);
1320         menu->insertSeparator();
1321         menu->insertItem("&Help", helpMenu);
1322         showIntroAction->addTo(helpMenu);
1323         showAboutAction->addTo(helpMenu);
1324
1325         connect(configList, SIGNAL(menuChanged(struct menu *)),
1326                 helpText, SLOT(setInfo(struct menu *)));
1327         connect(configList, SIGNAL(menuSelected(struct menu *)),
1328                 SLOT(changeMenu(struct menu *)));
1329         connect(configList, SIGNAL(parentSelected()),
1330                 SLOT(goBack()));
1331         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1332                 helpText, SLOT(setInfo(struct menu *)));
1333         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1334                 SLOT(changeMenu(struct menu *)));
1335
1336         connect(configList, SIGNAL(gotFocus(void)),
1337                 SLOT(listFocusChanged(void)));
1338         connect(menuList, SIGNAL(gotFocus(void)),
1339                 SLOT(listFocusChanged(void)));
1340
1341         QString listMode = configSettings->readEntry("/listMode", "symbol");
1342         if (listMode == "single")
1343                 showSingleView();
1344         else if (listMode == "full")
1345                 showFullView();
1346         else /*if (listMode == "split")*/
1347                 showSplitView();
1348
1349         // UI setup done, restore splitter positions
1350         QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1351         if (ok)
1352                 split1->setSizes(sizes);
1353
1354         sizes = configSettings->readSizes("/split2", &ok);
1355         if (ok)
1356                 split2->setSizes(sizes);
1357 }
1358
1359 /*
1360  * display a new help entry as soon as a new menu entry is selected
1361  */
1362 void ConfigMainWindow::setHelp(QListViewItem* item)
1363 {
1364         struct menu* menu = 0;
1365
1366         if (item)
1367                 menu = ((ConfigItem*)item)->menu;
1368         helpText->setInfo(menu);
1369 }
1370
1371 void ConfigMainWindow::loadConfig(void)
1372 {
1373         QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1374         if (s.isNull())
1375                 return;
1376         if (conf_read(QFile::encodeName(s)))
1377                 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1378         ConfigView::updateListAll();
1379 }
1380
1381 void ConfigMainWindow::saveConfig(void)
1382 {
1383         if (conf_write(NULL))
1384                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1385 }
1386
1387 void ConfigMainWindow::saveConfigAs(void)
1388 {
1389         QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1390         if (s.isNull())
1391                 return;
1392         if (conf_write(QFile::encodeName(s)))
1393                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1394 }
1395
1396 void ConfigMainWindow::searchConfig(void)
1397 {
1398         if (!searchWindow)
1399                 searchWindow = new ConfigSearchWindow(this, "search");
1400         searchWindow->show();
1401 }
1402
1403 void ConfigMainWindow::changeMenu(struct menu *menu)
1404 {
1405         configList->setRootMenu(menu);
1406         backAction->setEnabled(TRUE);
1407 }
1408
1409 void ConfigMainWindow::listFocusChanged(void)
1410 {
1411         if (menuList->hasFocus()) {
1412                 if (menuList->mode == menuMode)
1413                         configList->clearSelection();
1414                 setHelp(menuList->selectedItem());
1415         } else if (configList->hasFocus()) {
1416                 setHelp(configList->selectedItem());
1417         }
1418 }
1419
1420 void ConfigMainWindow::goBack(void)
1421 {
1422         ConfigItem* item;
1423
1424         configList->setParentMenu();
1425         if (configList->rootEntry == &rootmenu)
1426                 backAction->setEnabled(FALSE);
1427         item = (ConfigItem*)menuList->selectedItem();
1428         while (item) {
1429                 if (item->menu == configList->rootEntry) {
1430                         menuList->setSelected(item, TRUE);
1431                         break;
1432                 }
1433                 item = (ConfigItem*)item->parent();
1434         }
1435 }
1436
1437 void ConfigMainWindow::showSingleView(void)
1438 {
1439         menuView->hide();
1440         menuList->setRootMenu(0);
1441         configList->mode = singleMode;
1442         if (configList->rootEntry == &rootmenu)
1443                 configList->updateListAll();
1444         else
1445                 configList->setRootMenu(&rootmenu);
1446         configList->setAllOpen(TRUE);
1447         configList->setFocus();
1448 }
1449
1450 void ConfigMainWindow::showSplitView(void)
1451 {
1452         configList->mode = symbolMode;
1453         if (configList->rootEntry == &rootmenu)
1454                 configList->updateListAll();
1455         else
1456                 configList->setRootMenu(&rootmenu);
1457         configList->setAllOpen(TRUE);
1458         configApp->processEvents();
1459         menuList->mode = menuMode;
1460         menuList->setRootMenu(&rootmenu);
1461         menuList->setAllOpen(TRUE);
1462         menuView->show();
1463         menuList->setFocus();
1464 }
1465
1466 void ConfigMainWindow::showFullView(void)
1467 {
1468         menuView->hide();
1469         menuList->setRootMenu(0);
1470         configList->mode = fullMode;
1471         if (configList->rootEntry == &rootmenu)
1472                 configList->updateListAll();
1473         else
1474                 configList->setRootMenu(&rootmenu);
1475         configList->setAllOpen(FALSE);
1476         configList->setFocus();
1477 }
1478
1479 /*
1480  * ask for saving configuration before quitting
1481  * TODO ask only when something changed
1482  */
1483 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1484 {
1485         if (!sym_change_count) {
1486                 e->accept();
1487                 return;
1488         }
1489         QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1490                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1491         mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1492         mb.setButtonText(QMessageBox::No, "&Discard Changes");
1493         mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1494         switch (mb.exec()) {
1495         case QMessageBox::Yes:
1496                 conf_write(NULL);
1497         case QMessageBox::No:
1498                 e->accept();
1499                 break;
1500         case QMessageBox::Cancel:
1501                 e->ignore();
1502                 break;
1503         }
1504 }
1505
1506 void ConfigMainWindow::showIntro(void)
1507 {
1508         static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1509                 "For each option, a blank box indicates the feature is disabled, a check\n"
1510                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1511                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1512                 "If you do not see an option (e.g., a device driver) that you believe\n"
1513                 "should be present, try turning on Show All Options under the Options menu.\n"
1514                 "Although there is no cross reference yet to help you figure out what other\n"
1515                 "options must be enabled to support the option you are interested in, you can\n"
1516                 "still view the help of a grayed-out option.\n\n"
1517                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1518                 "which you can then match by examining other options.\n\n";
1519
1520         QMessageBox::information(this, "qconf", str);
1521 }
1522
1523 void ConfigMainWindow::showAbout(void)
1524 {
1525         static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1526                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1527
1528         QMessageBox::information(this, "qconf", str);
1529 }
1530
1531 void ConfigMainWindow::saveSettings(void)
1532 {
1533         configSettings->writeEntry("/window x", pos().x());
1534         configSettings->writeEntry("/window y", pos().y());
1535         configSettings->writeEntry("/window width", size().width());
1536         configSettings->writeEntry("/window height", size().height());
1537
1538         QString entry;
1539         switch(configList->mode) {
1540         case singleMode :
1541                 entry = "single";
1542                 break;
1543
1544         case symbolMode :
1545                 entry = "split";
1546                 break;
1547
1548         case fullMode :
1549                 entry = "full";
1550                 break;
1551         }
1552         configSettings->writeEntry("/listMode", entry);
1553
1554         configSettings->writeSizes("/split1", split1->sizes());
1555         configSettings->writeSizes("/split2", split2->sizes());
1556 }
1557
1558 void fixup_rootmenu(struct menu *menu)
1559 {
1560         struct menu *child;
1561         static int menu_cnt = 0;
1562
1563         menu->flags |= MENU_ROOT;
1564         for (child = menu->list; child; child = child->next) {
1565                 if (child->prompt && child->prompt->type == P_MENU) {
1566                         menu_cnt++;
1567                         fixup_rootmenu(child);
1568                         menu_cnt--;
1569                 } else if (!menu_cnt)
1570                         fixup_rootmenu(child);
1571         }
1572 }
1573
1574 static const char *progname;
1575
1576 static void usage(void)
1577 {
1578         printf("%s <config>\n", progname);
1579         exit(0);
1580 }
1581
1582 int main(int ac, char** av)
1583 {
1584         ConfigMainWindow* v;
1585         const char *name;
1586
1587         bindtextdomain(PACKAGE, LOCALEDIR);
1588         textdomain(PACKAGE);
1589
1590 #ifndef LKC_DIRECT_LINK
1591         kconfig_load();
1592 #endif
1593
1594         progname = av[0];
1595         configApp = new QApplication(ac, av);
1596         if (ac > 1 && av[1][0] == '-') {
1597                 switch (av[1][1]) {
1598                 case 'h':
1599                 case '?':
1600                         usage();
1601                 }
1602                 name = av[2];
1603         } else
1604                 name = av[1];
1605         if (!name)
1606                 usage();
1607
1608         conf_parse(name);
1609         fixup_rootmenu(&rootmenu);
1610         conf_read(NULL);
1611         //zconfdump(stdout);
1612
1613         configSettings = new ConfigSettings();
1614         configSettings->beginGroup("/kconfig/qconf");
1615         v = new ConfigMainWindow();
1616
1617         //zconfdump(stdout);
1618         configApp->setMainWidget(v);
1619         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1620         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1621         v->show();
1622         configApp->exec();
1623
1624         configSettings->endGroup();
1625         delete configSettings;
1626
1627         return 0;
1628 }