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