kconfig: create links in info window
[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                 else if (sym)
929                         symbolInfo();
930                 emit showDebugChanged(b);
931         }
932 }
933
934 void ConfigInfoView::setInfo(struct menu *m)
935 {
936         menu = m;
937         if (!menu)
938                 clear();
939         else
940                 menuInfo();
941 }
942
943 void ConfigInfoView::setSource(const QString& name)
944 {
945         const char *p = name.latin1();
946
947         menu = NULL;
948         sym = NULL;
949
950         switch (p[0]) {
951         case 'm':
952                 struct menu *m;
953
954                 if (sscanf(p, "m%p", &m) == 1 && menu != m) {
955                         menu = m;
956                         menuInfo();
957                 }
958                 break;
959         case 's':
960                 struct symbol *s;
961
962                 if (sscanf(p, "s%p", &s) == 1 && sym != s) {
963                         sym = s;
964                         symbolInfo();
965                 }
966                 break;
967         }
968 }
969
970 void ConfigInfoView::symbolInfo(void)
971 {
972         QString str;
973
974         str += "<big>Symbol: <b>";
975         str += print_filter(sym->name);
976         str += "</b></big><br><br>value: ";
977         str += print_filter(sym_get_string_value(sym));
978         str += "<br>visibility: ";
979         str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
980         str += "<br>";
981         str += debug_info(sym);
982
983         setText(str);
984 }
985
986 void ConfigInfoView::menuInfo(void)
987 {
988         struct symbol* sym;
989         QString head, debug, help;
990
991         sym = menu->sym;
992         if (sym) {
993                 if (menu->prompt) {
994                         head += "<big><b>";
995                         head += print_filter(_(menu->prompt->text));
996                         head += "</b></big>";
997                         if (sym->name) {
998                                 head += " (";
999                                 if (showDebug())
1000                                         head += QString().sprintf("<a href=\"s%p\">", sym);
1001                                 head += print_filter(sym->name);
1002                                 if (showDebug())
1003                                         head += "</a>";
1004                                 head += ")";
1005                         }
1006                 } else if (sym->name) {
1007                         head += "<big><b>";
1008                         if (showDebug())
1009                                 head += QString().sprintf("<a href=\"s%p\">", sym);
1010                         head += print_filter(sym->name);
1011                         if (showDebug())
1012                                 head += "</a>";
1013                         head += "</b></big>";
1014                 }
1015                 head += "<br><br>";
1016
1017                 if (showDebug())
1018                         debug = debug_info(sym);
1019
1020                 help = print_filter(_(sym->help));
1021         } else if (menu->prompt) {
1022                 head += "<big><b>";
1023                 head += print_filter(_(menu->prompt->text));
1024                 head += "</b></big><br><br>";
1025                 if (showDebug()) {
1026                         if (menu->prompt->visible.expr) {
1027                                 debug += "&nbsp;&nbsp;dep: ";
1028                                 expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1029                                 debug += "<br><br>";
1030                         }
1031                 }
1032         }
1033         if (showDebug())
1034                 debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
1035
1036         setText(head + debug + help);
1037 }
1038
1039 QString ConfigInfoView::debug_info(struct symbol *sym)
1040 {
1041         QString debug;
1042
1043         debug += "type: ";
1044         debug += print_filter(sym_type_name(sym->type));
1045         if (sym_is_choice(sym))
1046                 debug += " (choice)";
1047         debug += "<br>";
1048         if (sym->rev_dep.expr) {
1049                 debug += "reverse dep: ";
1050                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1051                 debug += "<br>";
1052         }
1053         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1054                 switch (prop->type) {
1055                 case P_PROMPT:
1056                 case P_MENU:
1057                         debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
1058                         debug += print_filter(_(prop->text));
1059                         debug += "</a><br>";
1060                         break;
1061                 case P_DEFAULT:
1062                         debug += "default: ";
1063                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1064                         debug += "<br>";
1065                         break;
1066                 case P_CHOICE:
1067                         if (sym_is_choice(sym)) {
1068                                 debug += "choice: ";
1069                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1070                                 debug += "<br>";
1071                         }
1072                         break;
1073                 case P_SELECT:
1074                         debug += "select: ";
1075                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1076                         debug += "<br>";
1077                         break;
1078                 case P_RANGE:
1079                         debug += "range: ";
1080                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1081                         debug += "<br>";
1082                         break;
1083                 default:
1084                         debug += "unknown property: ";
1085                         debug += prop_get_type_name(prop->type);
1086                         debug += "<br>";
1087                 }
1088                 if (prop->visible.expr) {
1089                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1090                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1091                         debug += "<br>";
1092                 }
1093         }
1094         debug += "<br>";
1095
1096         return debug;
1097 }
1098
1099 QString ConfigInfoView::print_filter(const QString &str)
1100 {
1101         QRegExp re("[<>&\"\\n]");
1102         QString res = str;
1103         for (int i = 0; (i = res.find(re, i)) >= 0;) {
1104                 switch (res[i].latin1()) {
1105                 case '<':
1106                         res.replace(i, 1, "&lt;");
1107                         i += 4;
1108                         break;
1109                 case '>':
1110                         res.replace(i, 1, "&gt;");
1111                         i += 4;
1112                         break;
1113                 case '&':
1114                         res.replace(i, 1, "&amp;");
1115                         i += 5;
1116                         break;
1117                 case '"':
1118                         res.replace(i, 1, "&quot;");
1119                         i += 6;
1120                         break;
1121                 case '\n':
1122                         res.replace(i, 1, "<br>");
1123                         i += 4;
1124                         break;
1125                 }
1126         }
1127         return res;
1128 }
1129
1130 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1131 {
1132         QString* text = reinterpret_cast<QString*>(data);
1133         QString str2 = print_filter(str);
1134
1135         if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1136                 *text += QString().sprintf("<a href=\"s%p\">", sym);
1137                 *text += str2;
1138                 *text += "</a>";
1139         } else
1140                 *text += str2;
1141 }
1142
1143 QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
1144 {
1145         QPopupMenu* popup = Parent::createPopupMenu(pos);
1146         QAction* action = new QAction("Show Debug Info", 0, popup);
1147           action->setToggleAction(TRUE);
1148           connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1149           connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1150           action->setOn(showDebug());
1151         popup->insertSeparator();
1152         action->addTo(popup);
1153         return popup;
1154 }
1155
1156 void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
1157 {
1158         Parent::contentsContextMenuEvent(e);
1159 }
1160
1161 ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
1162         : Parent(parent, name), result(NULL)
1163 {
1164         setCaption("Search Config");
1165
1166         QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
1167         QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
1168         layout2->addWidget(new QLabel("Find:", this));
1169         editField = new QLineEdit(this);
1170         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1171         layout2->addWidget(editField);
1172         searchButton = new QPushButton("Search", this);
1173         searchButton->setAutoDefault(FALSE);
1174         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1175         layout2->addWidget(searchButton);
1176         layout1->addLayout(layout2);
1177
1178         split = new QSplitter(this);
1179         split->setOrientation(QSplitter::Vertical);
1180         list = new ConfigView(split, name);
1181         list->list->mode = listMode;
1182         info = new ConfigInfoView(split, name);
1183         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1184                 info, SLOT(setInfo(struct menu *)));
1185         layout1->addWidget(split);
1186
1187         if (name) {
1188                 int x, y, width, height;
1189                 bool ok;
1190
1191                 configSettings->beginGroup(name);
1192                 width = configSettings->readNumEntry("/window width", parent->width() / 2);
1193                 height = configSettings->readNumEntry("/window height", parent->height() / 2);
1194                 resize(width, height);
1195                 x = configSettings->readNumEntry("/window x", 0, &ok);
1196                 if (ok)
1197                         y = configSettings->readNumEntry("/window y", 0, &ok);
1198                 if (ok)
1199                         move(x, y);
1200                 QValueList<int> sizes = configSettings->readSizes("/split", &ok);
1201                 if (ok)
1202                         split->setSizes(sizes);
1203                 configSettings->endGroup();
1204                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1205         }
1206 }
1207
1208 void ConfigSearchWindow::saveSettings(void)
1209 {
1210         if (name()) {
1211                 configSettings->beginGroup(name());
1212                 configSettings->writeEntry("/window x", pos().x());
1213                 configSettings->writeEntry("/window y", pos().y());
1214                 configSettings->writeEntry("/window width", size().width());
1215                 configSettings->writeEntry("/window height", size().height());
1216                 configSettings->writeSizes("/split", split->sizes());
1217                 configSettings->endGroup();
1218         }
1219 }
1220
1221 void ConfigSearchWindow::search(void)
1222 {
1223         struct symbol **p;
1224         struct property *prop;
1225         ConfigItem *lastItem = NULL;
1226
1227         free(result);
1228         list->list->clear();
1229
1230         result = sym_re_search(editField->text().latin1());
1231         if (!result)
1232                 return;
1233         for (p = result; *p; p++) {
1234                 for_all_prompts((*p), prop)
1235                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1236                                                   menu_is_visible(prop->menu));
1237         }
1238 }
1239
1240 /*
1241  * Construct the complete config widget
1242  */
1243 ConfigMainWindow::ConfigMainWindow(void)
1244 {
1245         QMenuBar* menu;
1246         bool ok;
1247         int x, y, width, height;
1248
1249         QWidget *d = configApp->desktop();
1250
1251         width = configSettings->readNumEntry("/window width", d->width() - 64);
1252         height = configSettings->readNumEntry("/window height", d->height() - 64);
1253         resize(width, height);
1254         x = configSettings->readNumEntry("/window x", 0, &ok);
1255         if (ok)
1256                 y = configSettings->readNumEntry("/window y", 0, &ok);
1257         if (ok)
1258                 move(x, y);
1259
1260         split1 = new QSplitter(this);
1261         split1->setOrientation(QSplitter::Horizontal);
1262         setCentralWidget(split1);
1263
1264         menuView = new ConfigView(split1, "menu");
1265         menuList = menuView->list;
1266
1267         split2 = new QSplitter(split1);
1268         split2->setOrientation(QSplitter::Vertical);
1269
1270         // create config tree
1271         configView = new ConfigView(split2, "config");
1272         configList = configView->list;
1273
1274         helpText = new ConfigInfoView(split2, "help");
1275         helpText->setTextFormat(Qt::RichText);
1276
1277         setTabOrder(configList, helpText);
1278         configList->setFocus();
1279
1280         menu = menuBar();
1281         toolBar = new QToolBar("Tools", this);
1282
1283         backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
1284           connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1285           backAction->setEnabled(FALSE);
1286         QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
1287           connect(quitAction, SIGNAL(activated()), SLOT(close()));
1288         QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
1289           connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1290         QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
1291           connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1292         QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
1293           connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1294         QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
1295           connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1296         QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
1297           connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1298         QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
1299           connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1300         QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
1301           connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1302
1303         QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
1304           showNameAction->setToggleAction(TRUE);
1305           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1306           connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1307           showNameAction->setOn(configView->showName());
1308         QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
1309           showRangeAction->setToggleAction(TRUE);
1310           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1311           connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1312           showRangeAction->setOn(configList->showRange);
1313         QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
1314           showDataAction->setToggleAction(TRUE);
1315           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1316           connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1317           showDataAction->setOn(configList->showData);
1318         QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
1319           showAllAction->setToggleAction(TRUE);
1320           connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
1321           connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
1322           showAllAction->setOn(configList->showAll);
1323         QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
1324           showDebugAction->setToggleAction(TRUE);
1325           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1326           connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1327           showDebugAction->setOn(helpText->showDebug());
1328
1329         QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
1330           connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1331         QAction *showAboutAction = new QAction(NULL, "About", 0, this);
1332           connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1333
1334         // init tool bar
1335         backAction->addTo(toolBar);
1336         toolBar->addSeparator();
1337         loadAction->addTo(toolBar);
1338         saveAction->addTo(toolBar);
1339         toolBar->addSeparator();
1340         singleViewAction->addTo(toolBar);
1341         splitViewAction->addTo(toolBar);
1342         fullViewAction->addTo(toolBar);
1343
1344         // create config menu
1345         QPopupMenu* config = new QPopupMenu(this);
1346         menu->insertItem("&File", config);
1347         loadAction->addTo(config);
1348         saveAction->addTo(config);
1349         saveAsAction->addTo(config);
1350         config->insertSeparator();
1351         searchAction->addTo(config);
1352         config->insertSeparator();
1353         quitAction->addTo(config);
1354
1355         // create options menu
1356         QPopupMenu* optionMenu = new QPopupMenu(this);
1357         menu->insertItem("&Option", optionMenu);
1358         showNameAction->addTo(optionMenu);
1359         showRangeAction->addTo(optionMenu);
1360         showDataAction->addTo(optionMenu);
1361         optionMenu->insertSeparator();
1362         showAllAction->addTo(optionMenu);
1363         showDebugAction->addTo(optionMenu);
1364
1365         // create help menu
1366         QPopupMenu* helpMenu = new QPopupMenu(this);
1367         menu->insertSeparator();
1368         menu->insertItem("&Help", helpMenu);
1369         showIntroAction->addTo(helpMenu);
1370         showAboutAction->addTo(helpMenu);
1371
1372         connect(configList, SIGNAL(menuChanged(struct menu *)),
1373                 helpText, SLOT(setInfo(struct menu *)));
1374         connect(configList, SIGNAL(menuSelected(struct menu *)),
1375                 SLOT(changeMenu(struct menu *)));
1376         connect(configList, SIGNAL(parentSelected()),
1377                 SLOT(goBack()));
1378         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1379                 helpText, SLOT(setInfo(struct menu *)));
1380         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1381                 SLOT(changeMenu(struct menu *)));
1382
1383         connect(configList, SIGNAL(gotFocus(void)),
1384                 SLOT(listFocusChanged(void)));
1385         connect(menuList, SIGNAL(gotFocus(void)),
1386                 SLOT(listFocusChanged(void)));
1387
1388         QString listMode = configSettings->readEntry("/listMode", "symbol");
1389         if (listMode == "single")
1390                 showSingleView();
1391         else if (listMode == "full")
1392                 showFullView();
1393         else /*if (listMode == "split")*/
1394                 showSplitView();
1395
1396         // UI setup done, restore splitter positions
1397         QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1398         if (ok)
1399                 split1->setSizes(sizes);
1400
1401         sizes = configSettings->readSizes("/split2", &ok);
1402         if (ok)
1403                 split2->setSizes(sizes);
1404 }
1405
1406 /*
1407  * display a new help entry as soon as a new menu entry is selected
1408  */
1409 void ConfigMainWindow::setHelp(QListViewItem* item)
1410 {
1411         struct menu* menu = 0;
1412
1413         if (item)
1414                 menu = ((ConfigItem*)item)->menu;
1415         helpText->setInfo(menu);
1416 }
1417
1418 void ConfigMainWindow::loadConfig(void)
1419 {
1420         QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1421         if (s.isNull())
1422                 return;
1423         if (conf_read(QFile::encodeName(s)))
1424                 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1425         ConfigView::updateListAll();
1426 }
1427
1428 void ConfigMainWindow::saveConfig(void)
1429 {
1430         if (conf_write(NULL))
1431                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1432 }
1433
1434 void ConfigMainWindow::saveConfigAs(void)
1435 {
1436         QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1437         if (s.isNull())
1438                 return;
1439         if (conf_write(QFile::encodeName(s)))
1440                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1441 }
1442
1443 void ConfigMainWindow::searchConfig(void)
1444 {
1445         if (!searchWindow)
1446                 searchWindow = new ConfigSearchWindow(this, "search");
1447         searchWindow->show();
1448 }
1449
1450 void ConfigMainWindow::changeMenu(struct menu *menu)
1451 {
1452         configList->setRootMenu(menu);
1453         backAction->setEnabled(TRUE);
1454 }
1455
1456 void ConfigMainWindow::listFocusChanged(void)
1457 {
1458         if (menuList->hasFocus()) {
1459                 if (menuList->mode == menuMode)
1460                         configList->clearSelection();
1461                 setHelp(menuList->selectedItem());
1462         } else if (configList->hasFocus()) {
1463                 setHelp(configList->selectedItem());
1464         }
1465 }
1466
1467 void ConfigMainWindow::goBack(void)
1468 {
1469         ConfigItem* item;
1470
1471         configList->setParentMenu();
1472         if (configList->rootEntry == &rootmenu)
1473                 backAction->setEnabled(FALSE);
1474         item = (ConfigItem*)menuList->selectedItem();
1475         while (item) {
1476                 if (item->menu == configList->rootEntry) {
1477                         menuList->setSelected(item, TRUE);
1478                         break;
1479                 }
1480                 item = (ConfigItem*)item->parent();
1481         }
1482 }
1483
1484 void ConfigMainWindow::showSingleView(void)
1485 {
1486         menuView->hide();
1487         menuList->setRootMenu(0);
1488         configList->mode = singleMode;
1489         if (configList->rootEntry == &rootmenu)
1490                 configList->updateListAll();
1491         else
1492                 configList->setRootMenu(&rootmenu);
1493         configList->setAllOpen(TRUE);
1494         configList->setFocus();
1495 }
1496
1497 void ConfigMainWindow::showSplitView(void)
1498 {
1499         configList->mode = symbolMode;
1500         if (configList->rootEntry == &rootmenu)
1501                 configList->updateListAll();
1502         else
1503                 configList->setRootMenu(&rootmenu);
1504         configList->setAllOpen(TRUE);
1505         configApp->processEvents();
1506         menuList->mode = menuMode;
1507         menuList->setRootMenu(&rootmenu);
1508         menuList->setAllOpen(TRUE);
1509         menuView->show();
1510         menuList->setFocus();
1511 }
1512
1513 void ConfigMainWindow::showFullView(void)
1514 {
1515         menuView->hide();
1516         menuList->setRootMenu(0);
1517         configList->mode = fullMode;
1518         if (configList->rootEntry == &rootmenu)
1519                 configList->updateListAll();
1520         else
1521                 configList->setRootMenu(&rootmenu);
1522         configList->setAllOpen(FALSE);
1523         configList->setFocus();
1524 }
1525
1526 /*
1527  * ask for saving configuration before quitting
1528  * TODO ask only when something changed
1529  */
1530 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1531 {
1532         if (!sym_change_count) {
1533                 e->accept();
1534                 return;
1535         }
1536         QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1537                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1538         mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1539         mb.setButtonText(QMessageBox::No, "&Discard Changes");
1540         mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1541         switch (mb.exec()) {
1542         case QMessageBox::Yes:
1543                 conf_write(NULL);
1544         case QMessageBox::No:
1545                 e->accept();
1546                 break;
1547         case QMessageBox::Cancel:
1548                 e->ignore();
1549                 break;
1550         }
1551 }
1552
1553 void ConfigMainWindow::showIntro(void)
1554 {
1555         static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1556                 "For each option, a blank box indicates the feature is disabled, a check\n"
1557                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1558                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1559                 "If you do not see an option (e.g., a device driver) that you believe\n"
1560                 "should be present, try turning on Show All Options under the Options menu.\n"
1561                 "Although there is no cross reference yet to help you figure out what other\n"
1562                 "options must be enabled to support the option you are interested in, you can\n"
1563                 "still view the help of a grayed-out option.\n\n"
1564                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1565                 "which you can then match by examining other options.\n\n";
1566
1567         QMessageBox::information(this, "qconf", str);
1568 }
1569
1570 void ConfigMainWindow::showAbout(void)
1571 {
1572         static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1573                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1574
1575         QMessageBox::information(this, "qconf", str);
1576 }
1577
1578 void ConfigMainWindow::saveSettings(void)
1579 {
1580         configSettings->writeEntry("/window x", pos().x());
1581         configSettings->writeEntry("/window y", pos().y());
1582         configSettings->writeEntry("/window width", size().width());
1583         configSettings->writeEntry("/window height", size().height());
1584
1585         QString entry;
1586         switch(configList->mode) {
1587         case singleMode :
1588                 entry = "single";
1589                 break;
1590
1591         case symbolMode :
1592                 entry = "split";
1593                 break;
1594
1595         case fullMode :
1596                 entry = "full";
1597                 break;
1598         }
1599         configSettings->writeEntry("/listMode", entry);
1600
1601         configSettings->writeSizes("/split1", split1->sizes());
1602         configSettings->writeSizes("/split2", split2->sizes());
1603 }
1604
1605 void fixup_rootmenu(struct menu *menu)
1606 {
1607         struct menu *child;
1608         static int menu_cnt = 0;
1609
1610         menu->flags |= MENU_ROOT;
1611         for (child = menu->list; child; child = child->next) {
1612                 if (child->prompt && child->prompt->type == P_MENU) {
1613                         menu_cnt++;
1614                         fixup_rootmenu(child);
1615                         menu_cnt--;
1616                 } else if (!menu_cnt)
1617                         fixup_rootmenu(child);
1618         }
1619 }
1620
1621 static const char *progname;
1622
1623 static void usage(void)
1624 {
1625         printf("%s <config>\n", progname);
1626         exit(0);
1627 }
1628
1629 int main(int ac, char** av)
1630 {
1631         ConfigMainWindow* v;
1632         const char *name;
1633
1634         bindtextdomain(PACKAGE, LOCALEDIR);
1635         textdomain(PACKAGE);
1636
1637 #ifndef LKC_DIRECT_LINK
1638         kconfig_load();
1639 #endif
1640
1641         progname = av[0];
1642         configApp = new QApplication(ac, av);
1643         if (ac > 1 && av[1][0] == '-') {
1644                 switch (av[1][1]) {
1645                 case 'h':
1646                 case '?':
1647                         usage();
1648                 }
1649                 name = av[2];
1650         } else
1651                 name = av[1];
1652         if (!name)
1653                 usage();
1654
1655         conf_parse(name);
1656         fixup_rootmenu(&rootmenu);
1657         conf_read(NULL);
1658         //zconfdump(stdout);
1659
1660         configSettings = new ConfigSettings();
1661         configSettings->beginGroup("/kconfig/qconf");
1662         v = new ConfigMainWindow();
1663
1664         //zconfdump(stdout);
1665         configApp->setMainWidget(v);
1666         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1667         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1668         v->show();
1669         configApp->exec();
1670
1671         configSettings->endGroup();
1672         delete configSettings;
1673
1674         return 0;
1675 }