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