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