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