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