Merge branch 'devel-stable' into devel
[sfrench/cifs-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 <qdesktopwidget.h>
9 #include <qtoolbar.h>
10 #include <qlayout.h>
11 #include <qvbox.h>
12 #include <qsplitter.h>
13 #include <qlistview.h>
14 #include <qtextbrowser.h>
15 #include <qlineedit.h>
16 #include <qlabel.h>
17 #include <qpushbutton.h>
18 #include <qmenubar.h>
19 #include <qmessagebox.h>
20 #include <qaction.h>
21 #include <qheader.h>
22 #include <qfiledialog.h>
23 #include <qdragobject.h>
24 #include <qregexp.h>
25
26 #include <stdlib.h>
27
28 #include "lkc.h"
29 #include "qconf.h"
30
31 #include "qconf.moc"
32 #include "images.c"
33
34 #ifdef _
35 # undef _
36 # define _ qgettext
37 #endif
38
39 static QApplication *configApp;
40 static ConfigSettings *configSettings;
41
42 QAction *ConfigMainWindow::saveAction;
43
44 static inline QString qgettext(const char* str)
45 {
46         return QString::fromLocal8Bit(gettext(str));
47 }
48
49 static inline QString qgettext(const QString& str)
50 {
51         return QString::fromLocal8Bit(gettext(str.latin1()));
52 }
53
54 /**
55  * Reads a list of integer values from the application settings.
56  */
57 QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
58 {
59         QValueList<int> result;
60         QStringList entryList = readListEntry(key, ok);
61         QStringList::Iterator it;
62
63         for (it = entryList.begin(); it != entryList.end(); ++it)
64                 result.push_back((*it).toInt());
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->optMode == normalOpt) {
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 Qt::Key_Escape:
301                 break;
302         case Qt::Key_Return:
303         case Qt::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           showName(false), showRange(false), showData(false), optMode(normalOpt),
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                 showName = configSettings->readBoolEntry("/showName", false);
340                 showRange = configSettings->readBoolEntry("/showRange", false);
341                 showData = configSettings->readBoolEntry("/showData", false);
342                 optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", 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 bool ConfigList::menuSkip(struct menu *menu)
355 {
356         if (optMode == normalOpt && menu_is_visible(menu))
357                 return false;
358         if (optMode == promptOpt && menu_has_prompt(menu))
359                 return false;
360         if (optMode == allOpt)
361                 return false;
362         return true;
363 }
364
365 void ConfigList::reinit(void)
366 {
367         removeColumn(dataColIdx);
368         removeColumn(yesColIdx);
369         removeColumn(modColIdx);
370         removeColumn(noColIdx);
371         removeColumn(nameColIdx);
372
373         if (showName)
374                 addColumn(nameColIdx, _("Name"));
375         if (showRange) {
376                 addColumn(noColIdx, "N");
377                 addColumn(modColIdx, "M");
378                 addColumn(yesColIdx, "Y");
379         }
380         if (showData)
381                 addColumn(dataColIdx, _("Value"));
382
383         updateListAll();
384 }
385
386 void ConfigList::saveSettings(void)
387 {
388         if (name()) {
389                 configSettings->beginGroup(name());
390                 configSettings->writeEntry("/showName", showName);
391                 configSettings->writeEntry("/showRange", showRange);
392                 configSettings->writeEntry("/showData", showData);
393                 configSettings->writeEntry("/optionMode", (int)optMode);
394                 configSettings->endGroup();
395         }
396 }
397
398 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
399 {
400         ConfigItem* item = (ConfigItem*)menu->data;
401
402         for (; item; item = item->nextItem) {
403                 if (this == item->listView())
404                         break;
405         }
406
407         return item;
408 }
409
410 void ConfigList::updateSelection(void)
411 {
412         struct menu *menu;
413         enum prop_type type;
414
415         ConfigItem* item = (ConfigItem*)selectedItem();
416         if (!item)
417                 return;
418
419         menu = item->menu;
420         emit menuChanged(menu);
421         if (!menu)
422                 return;
423         type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
424         if (mode == menuMode && type == P_MENU)
425                 emit menuSelected(menu);
426 }
427
428 void ConfigList::updateList(ConfigItem* item)
429 {
430         ConfigItem* last = 0;
431
432         if (!rootEntry) {
433                 if (mode != listMode)
434                         goto update;
435                 QListViewItemIterator it(this);
436                 ConfigItem* item;
437
438                 for (; it.current(); ++it) {
439                         item = (ConfigItem*)it.current();
440                         if (!item->menu)
441                                 continue;
442                         item->testUpdateMenu(menu_is_visible(item->menu));
443                 }
444                 return;
445         }
446
447         if (rootEntry != &rootmenu && (mode == singleMode ||
448             (mode == symbolMode && rootEntry->parent != &rootmenu))) {
449                 item = firstChild();
450                 if (!item)
451                         item = new ConfigItem(this, 0, true);
452                 last = item;
453         }
454         if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
455             rootEntry->sym && rootEntry->prompt) {
456                 item = last ? last->nextSibling() : firstChild();
457                 if (!item)
458                         item = new ConfigItem(this, last, rootEntry, true);
459                 else
460                         item->testUpdateMenu(true);
461
462                 updateMenuList(item, rootEntry);
463                 triggerUpdate();
464                 return;
465         }
466 update:
467         updateMenuList(this, rootEntry);
468         triggerUpdate();
469 }
470
471 void ConfigList::setValue(ConfigItem* item, tristate val)
472 {
473         struct symbol* sym;
474         int type;
475         tristate oldval;
476
477         sym = item->menu ? item->menu->sym : 0;
478         if (!sym)
479                 return;
480
481         type = sym_get_type(sym);
482         switch (type) {
483         case S_BOOLEAN:
484         case S_TRISTATE:
485                 oldval = sym_get_tristate_value(sym);
486
487                 if (!sym_set_tristate_value(sym, val))
488                         return;
489                 if (oldval == no && item->menu->list)
490                         item->setOpen(TRUE);
491                 parent()->updateList(item);
492                 break;
493         }
494 }
495
496 void ConfigList::changeValue(ConfigItem* item)
497 {
498         struct symbol* sym;
499         struct menu* menu;
500         int type, oldexpr, newexpr;
501
502         menu = item->menu;
503         if (!menu)
504                 return;
505         sym = menu->sym;
506         if (!sym) {
507                 if (item->menu->list)
508                         item->setOpen(!item->isOpen());
509                 return;
510         }
511
512         type = sym_get_type(sym);
513         switch (type) {
514         case S_BOOLEAN:
515         case S_TRISTATE:
516                 oldexpr = sym_get_tristate_value(sym);
517                 newexpr = sym_toggle_tristate_value(sym);
518                 if (item->menu->list) {
519                         if (oldexpr == newexpr)
520                                 item->setOpen(!item->isOpen());
521                         else if (oldexpr == no)
522                                 item->setOpen(TRUE);
523                 }
524                 if (oldexpr != newexpr)
525                         parent()->updateList(item);
526                 break;
527         case S_INT:
528         case S_HEX:
529         case S_STRING:
530 #if QT_VERSION >= 300
531                 if (colMap[dataColIdx] >= 0)
532                         item->startRename(colMap[dataColIdx]);
533                 else
534 #endif
535                         parent()->lineEdit->show(item);
536                 break;
537         }
538 }
539
540 void ConfigList::setRootMenu(struct menu *menu)
541 {
542         enum prop_type type;
543
544         if (rootEntry == menu)
545                 return;
546         type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
547         if (type != P_MENU)
548                 return;
549         updateMenuList(this, 0);
550         rootEntry = menu;
551         updateListAll();
552         setSelected(currentItem(), hasFocus());
553         ensureItemVisible(currentItem());
554 }
555
556 void ConfigList::setParentMenu(void)
557 {
558         ConfigItem* item;
559         struct menu *oldroot;
560
561         oldroot = rootEntry;
562         if (rootEntry == &rootmenu)
563                 return;
564         setRootMenu(menu_get_parent_menu(rootEntry->parent));
565
566         QListViewItemIterator it(this);
567         for (; (item = (ConfigItem*)it.current()); it++) {
568                 if (item->menu == oldroot) {
569                         setCurrentItem(item);
570                         ensureItemVisible(item);
571                         break;
572                 }
573         }
574 }
575
576 /*
577  * update all the children of a menu entry
578  *   removes/adds the entries from the parent widget as necessary
579  *
580  * parent: either the menu list widget or a menu entry widget
581  * menu: entry to be updated
582  */
583 template <class P>
584 void ConfigList::updateMenuList(P* parent, struct menu* menu)
585 {
586         struct menu* child;
587         ConfigItem* item;
588         ConfigItem* last;
589         bool visible;
590         enum prop_type type;
591
592         if (!menu) {
593                 while ((item = parent->firstChild()))
594                         delete item;
595                 return;
596         }
597
598         last = parent->firstChild();
599         if (last && !last->goParent)
600                 last = 0;
601         for (child = menu->list; child; child = child->next) {
602                 item = last ? last->nextSibling() : parent->firstChild();
603                 type = child->prompt ? child->prompt->type : P_UNKNOWN;
604
605                 switch (mode) {
606                 case menuMode:
607                         if (!(child->flags & MENU_ROOT))
608                                 goto hide;
609                         break;
610                 case symbolMode:
611                         if (child->flags & MENU_ROOT)
612                                 goto hide;
613                         break;
614                 default:
615                         break;
616                 }
617
618                 visible = menu_is_visible(child);
619                 if (!menuSkip(child)) {
620                         if (!child->sym && !child->list && !child->prompt)
621                                 continue;
622                         if (!item || item->menu != child)
623                                 item = new ConfigItem(parent, last, child, visible);
624                         else
625                                 item->testUpdateMenu(visible);
626
627                         if (mode == fullMode || mode == menuMode || type != P_MENU)
628                                 updateMenuList(item, child);
629                         else
630                                 updateMenuList(item, 0);
631                         last = item;
632                         continue;
633                 }
634         hide:
635                 if (item && item->menu == child) {
636                         last = parent->firstChild();
637                         if (last == item)
638                                 last = 0;
639                         else while (last->nextSibling() != item)
640                                 last = last->nextSibling();
641                         delete item;
642                 }
643         }
644 }
645
646 void ConfigList::keyPressEvent(QKeyEvent* ev)
647 {
648         QListViewItem* i = currentItem();
649         ConfigItem* item;
650         struct menu *menu;
651         enum prop_type type;
652
653         if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
654                 emit parentSelected();
655                 ev->accept();
656                 return;
657         }
658
659         if (!i) {
660                 Parent::keyPressEvent(ev);
661                 return;
662         }
663         item = (ConfigItem*)i;
664
665         switch (ev->key()) {
666         case Qt::Key_Return:
667         case Qt::Key_Enter:
668                 if (item->goParent) {
669                         emit parentSelected();
670                         break;
671                 }
672                 menu = item->menu;
673                 if (!menu)
674                         break;
675                 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
676                 if (type == P_MENU && rootEntry != menu &&
677                     mode != fullMode && mode != menuMode) {
678                         emit menuSelected(menu);
679                         break;
680                 }
681         case Qt::Key_Space:
682                 changeValue(item);
683                 break;
684         case Qt::Key_N:
685                 setValue(item, no);
686                 break;
687         case Qt::Key_M:
688                 setValue(item, mod);
689                 break;
690         case Qt::Key_Y:
691                 setValue(item, yes);
692                 break;
693         default:
694                 Parent::keyPressEvent(ev);
695                 return;
696         }
697         ev->accept();
698 }
699
700 void ConfigList::contentsMousePressEvent(QMouseEvent* e)
701 {
702         //QPoint p(contentsToViewport(e->pos()));
703         //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
704         Parent::contentsMousePressEvent(e);
705 }
706
707 void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
708 {
709         QPoint p(contentsToViewport(e->pos()));
710         ConfigItem* item = (ConfigItem*)itemAt(p);
711         struct menu *menu;
712         enum prop_type ptype;
713         const QPixmap* pm;
714         int idx, x;
715
716         if (!item)
717                 goto skip;
718
719         menu = item->menu;
720         x = header()->offset() + p.x();
721         idx = colRevMap[header()->sectionAt(x)];
722         switch (idx) {
723         case promptColIdx:
724                 pm = item->pixmap(promptColIdx);
725                 if (pm) {
726                         int off = header()->sectionPos(0) + itemMargin() +
727                                 treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
728                         if (x >= off && x < off + pm->width()) {
729                                 if (item->goParent) {
730                                         emit parentSelected();
731                                         break;
732                                 } else if (!menu)
733                                         break;
734                                 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
735                                 if (ptype == P_MENU && rootEntry != menu &&
736                                     mode != fullMode && mode != menuMode)
737                                         emit menuSelected(menu);
738                                 else
739                                         changeValue(item);
740                         }
741                 }
742                 break;
743         case noColIdx:
744                 setValue(item, no);
745                 break;
746         case modColIdx:
747                 setValue(item, mod);
748                 break;
749         case yesColIdx:
750                 setValue(item, yes);
751                 break;
752         case dataColIdx:
753                 changeValue(item);
754                 break;
755         }
756
757 skip:
758         //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
759         Parent::contentsMouseReleaseEvent(e);
760 }
761
762 void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
763 {
764         //QPoint p(contentsToViewport(e->pos()));
765         //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
766         Parent::contentsMouseMoveEvent(e);
767 }
768
769 void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
770 {
771         QPoint p(contentsToViewport(e->pos()));
772         ConfigItem* item = (ConfigItem*)itemAt(p);
773         struct menu *menu;
774         enum prop_type ptype;
775
776         if (!item)
777                 goto skip;
778         if (item->goParent) {
779                 emit parentSelected();
780                 goto skip;
781         }
782         menu = item->menu;
783         if (!menu)
784                 goto skip;
785         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
786         if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
787                 emit menuSelected(menu);
788         else if (menu->sym)
789                 changeValue(item);
790
791 skip:
792         //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
793         Parent::contentsMouseDoubleClickEvent(e);
794 }
795
796 void ConfigList::focusInEvent(QFocusEvent *e)
797 {
798         struct menu *menu = NULL;
799
800         Parent::focusInEvent(e);
801
802         ConfigItem* item = (ConfigItem *)currentItem();
803         if (item) {
804                 setSelected(item, TRUE);
805                 menu = item->menu;
806         }
807         emit gotFocus(menu);
808 }
809
810 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
811 {
812         if (e->y() <= header()->geometry().bottom()) {
813                 if (!headerPopup) {
814                         QAction *action;
815
816                         headerPopup = new QPopupMenu(this);
817                         action = new QAction(NULL, _("Show Name"), 0, this);
818                           action->setToggleAction(TRUE);
819                           connect(action, SIGNAL(toggled(bool)),
820                                   parent(), SLOT(setShowName(bool)));
821                           connect(parent(), SIGNAL(showNameChanged(bool)),
822                                   action, SLOT(setOn(bool)));
823                           action->setOn(showName);
824                           action->addTo(headerPopup);
825                         action = new QAction(NULL, _("Show Range"), 0, this);
826                           action->setToggleAction(TRUE);
827                           connect(action, SIGNAL(toggled(bool)),
828                                   parent(), SLOT(setShowRange(bool)));
829                           connect(parent(), SIGNAL(showRangeChanged(bool)),
830                                   action, SLOT(setOn(bool)));
831                           action->setOn(showRange);
832                           action->addTo(headerPopup);
833                         action = new QAction(NULL, _("Show Data"), 0, this);
834                           action->setToggleAction(TRUE);
835                           connect(action, SIGNAL(toggled(bool)),
836                                   parent(), SLOT(setShowData(bool)));
837                           connect(parent(), SIGNAL(showDataChanged(bool)),
838                                   action, SLOT(setOn(bool)));
839                           action->setOn(showData);
840                           action->addTo(headerPopup);
841                 }
842                 headerPopup->exec(e->globalPos());
843                 e->accept();
844         } else
845                 e->ignore();
846 }
847
848 ConfigView*ConfigView::viewList;
849 QAction *ConfigView::showNormalAction;
850 QAction *ConfigView::showAllAction;
851 QAction *ConfigView::showPromptAction;
852
853 ConfigView::ConfigView(QWidget* parent, const char *name)
854         : Parent(parent, name)
855 {
856         list = new ConfigList(this, name);
857         lineEdit = new ConfigLineEdit(this);
858         lineEdit->hide();
859
860         this->nextView = viewList;
861         viewList = this;
862 }
863
864 ConfigView::~ConfigView(void)
865 {
866         ConfigView** vp;
867
868         for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
869                 if (*vp == this) {
870                         *vp = nextView;
871                         break;
872                 }
873         }
874 }
875
876 void ConfigView::setOptionMode(QAction *act)
877 {
878         if (act == showNormalAction)
879                 list->optMode = normalOpt;
880         else if (act == showAllAction)
881                 list->optMode = allOpt;
882         else
883                 list->optMode = promptOpt;
884
885         list->updateListAll();
886 }
887
888 void ConfigView::setShowName(bool b)
889 {
890         if (list->showName != b) {
891                 list->showName = b;
892                 list->reinit();
893                 emit showNameChanged(b);
894         }
895 }
896
897 void ConfigView::setShowRange(bool b)
898 {
899         if (list->showRange != b) {
900                 list->showRange = b;
901                 list->reinit();
902                 emit showRangeChanged(b);
903         }
904 }
905
906 void ConfigView::setShowData(bool b)
907 {
908         if (list->showData != b) {
909                 list->showData = b;
910                 list->reinit();
911                 emit showDataChanged(b);
912         }
913 }
914
915 void ConfigList::setAllOpen(bool open)
916 {
917         QListViewItemIterator it(this);
918
919         for (; it.current(); it++)
920                 it.current()->setOpen(open);
921 }
922
923 void ConfigView::updateList(ConfigItem* item)
924 {
925         ConfigView* v;
926
927         for (v = viewList; v; v = v->nextView)
928                 v->list->updateList(item);
929 }
930
931 void ConfigView::updateListAll(void)
932 {
933         ConfigView* v;
934
935         for (v = viewList; v; v = v->nextView)
936                 v->list->updateListAll();
937 }
938
939 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
940         : Parent(parent, name), sym(0), menu(0)
941 {
942         if (name) {
943                 configSettings->beginGroup(name);
944                 _showDebug = configSettings->readBoolEntry("/showDebug", false);
945                 configSettings->endGroup();
946                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
947         }
948 }
949
950 void ConfigInfoView::saveSettings(void)
951 {
952         if (name()) {
953                 configSettings->beginGroup(name());
954                 configSettings->writeEntry("/showDebug", showDebug());
955                 configSettings->endGroup();
956         }
957 }
958
959 void ConfigInfoView::setShowDebug(bool b)
960 {
961         if (_showDebug != b) {
962                 _showDebug = b;
963                 if (menu)
964                         menuInfo();
965                 else if (sym)
966                         symbolInfo();
967                 emit showDebugChanged(b);
968         }
969 }
970
971 void ConfigInfoView::setInfo(struct menu *m)
972 {
973         if (menu == m)
974                 return;
975         menu = m;
976         sym = NULL;
977         if (!menu)
978                 clear();
979         else
980                 menuInfo();
981 }
982
983 void ConfigInfoView::symbolInfo(void)
984 {
985         QString str;
986
987         str += "<big>Symbol: <b>";
988         str += print_filter(sym->name);
989         str += "</b></big><br><br>value: ";
990         str += print_filter(sym_get_string_value(sym));
991         str += "<br>visibility: ";
992         str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
993         str += "<br>";
994         str += debug_info(sym);
995
996         setText(str);
997 }
998
999 void ConfigInfoView::menuInfo(void)
1000 {
1001         struct symbol* sym;
1002         QString head, debug, help;
1003
1004         sym = menu->sym;
1005         if (sym) {
1006                 if (menu->prompt) {
1007                         head += "<big><b>";
1008                         head += print_filter(_(menu->prompt->text));
1009                         head += "</b></big>";
1010                         if (sym->name) {
1011                                 head += " (";
1012                                 if (showDebug())
1013                                         head += QString().sprintf("<a href=\"s%p\">", sym);
1014                                 head += print_filter(sym->name);
1015                                 if (showDebug())
1016                                         head += "</a>";
1017                                 head += ")";
1018                         }
1019                 } else if (sym->name) {
1020                         head += "<big><b>";
1021                         if (showDebug())
1022                                 head += QString().sprintf("<a href=\"s%p\">", sym);
1023                         head += print_filter(sym->name);
1024                         if (showDebug())
1025                                 head += "</a>";
1026                         head += "</b></big>";
1027                 }
1028                 head += "<br><br>";
1029
1030                 if (showDebug())
1031                         debug = debug_info(sym);
1032
1033                 struct gstr help_gstr = str_new();
1034                 menu_get_ext_help(menu, &help_gstr);
1035                 help = print_filter(str_get(&help_gstr));
1036                 str_free(&help_gstr);
1037         } else if (menu->prompt) {
1038                 head += "<big><b>";
1039                 head += print_filter(_(menu->prompt->text));
1040                 head += "</b></big><br><br>";
1041                 if (showDebug()) {
1042                         if (menu->prompt->visible.expr) {
1043                                 debug += "&nbsp;&nbsp;dep: ";
1044                                 expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1045                                 debug += "<br><br>";
1046                         }
1047                 }
1048         }
1049         if (showDebug())
1050                 debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
1051
1052         setText(head + debug + help);
1053 }
1054
1055 QString ConfigInfoView::debug_info(struct symbol *sym)
1056 {
1057         QString debug;
1058
1059         debug += "type: ";
1060         debug += print_filter(sym_type_name(sym->type));
1061         if (sym_is_choice(sym))
1062                 debug += " (choice)";
1063         debug += "<br>";
1064         if (sym->rev_dep.expr) {
1065                 debug += "reverse dep: ";
1066                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1067                 debug += "<br>";
1068         }
1069         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1070                 switch (prop->type) {
1071                 case P_PROMPT:
1072                 case P_MENU:
1073                         debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
1074                         debug += print_filter(_(prop->text));
1075                         debug += "</a><br>";
1076                         break;
1077                 case P_DEFAULT:
1078                 case P_SELECT:
1079                 case P_RANGE:
1080                 case P_ENV:
1081                         debug += prop_get_type_name(prop->type);
1082                         debug += ": ";
1083                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1084                         debug += "<br>";
1085                         break;
1086                 case P_CHOICE:
1087                         if (sym_is_choice(sym)) {
1088                                 debug += "choice: ";
1089                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1090                                 debug += "<br>";
1091                         }
1092                         break;
1093                 default:
1094                         debug += "unknown property: ";
1095                         debug += prop_get_type_name(prop->type);
1096                         debug += "<br>";
1097                 }
1098                 if (prop->visible.expr) {
1099                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1100                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1101                         debug += "<br>";
1102                 }
1103         }
1104         debug += "<br>";
1105
1106         return debug;
1107 }
1108
1109 QString ConfigInfoView::print_filter(const QString &str)
1110 {
1111         QRegExp re("[<>&\"\\n]");
1112         QString res = str;
1113         for (int i = 0; (i = res.find(re, i)) >= 0;) {
1114                 switch (res[i].latin1()) {
1115                 case '<':
1116                         res.replace(i, 1, "&lt;");
1117                         i += 4;
1118                         break;
1119                 case '>':
1120                         res.replace(i, 1, "&gt;");
1121                         i += 4;
1122                         break;
1123                 case '&':
1124                         res.replace(i, 1, "&amp;");
1125                         i += 5;
1126                         break;
1127                 case '"':
1128                         res.replace(i, 1, "&quot;");
1129                         i += 6;
1130                         break;
1131                 case '\n':
1132                         res.replace(i, 1, "<br>");
1133                         i += 4;
1134                         break;
1135                 }
1136         }
1137         return res;
1138 }
1139
1140 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1141 {
1142         QString* text = reinterpret_cast<QString*>(data);
1143         QString str2 = print_filter(str);
1144
1145         if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1146                 *text += QString().sprintf("<a href=\"s%p\">", sym);
1147                 *text += str2;
1148                 *text += "</a>";
1149         } else
1150                 *text += str2;
1151 }
1152
1153 QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
1154 {
1155         QPopupMenu* popup = Parent::createPopupMenu(pos);
1156         QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup);
1157           action->setToggleAction(TRUE);
1158           connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1159           connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1160           action->setOn(showDebug());
1161         popup->insertSeparator();
1162         action->addTo(popup);
1163         return popup;
1164 }
1165
1166 void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
1167 {
1168         Parent::contentsContextMenuEvent(e);
1169 }
1170
1171 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1172         : Parent(parent, name), result(NULL)
1173 {
1174         setCaption("Search Config");
1175
1176         QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
1177         QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
1178         layout2->addWidget(new QLabel(_("Find:"), this));
1179         editField = new QLineEdit(this);
1180         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1181         layout2->addWidget(editField);
1182         searchButton = new QPushButton(_("Search"), this);
1183         searchButton->setAutoDefault(FALSE);
1184         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1185         layout2->addWidget(searchButton);
1186         layout1->addLayout(layout2);
1187
1188         split = new QSplitter(this);
1189         split->setOrientation(Qt::Vertical);
1190         list = new ConfigView(split, name);
1191         list->list->mode = listMode;
1192         info = new ConfigInfoView(split, name);
1193         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1194                 info, SLOT(setInfo(struct menu *)));
1195         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1196                 parent, SLOT(setMenuLink(struct menu *)));
1197
1198         layout1->addWidget(split);
1199
1200         if (name) {
1201                 int x, y, width, height;
1202                 bool ok;
1203
1204                 configSettings->beginGroup(name);
1205                 width = configSettings->readNumEntry("/window width", parent->width() / 2);
1206                 height = configSettings->readNumEntry("/window height", parent->height() / 2);
1207                 resize(width, height);
1208                 x = configSettings->readNumEntry("/window x", 0, &ok);
1209                 if (ok)
1210                         y = configSettings->readNumEntry("/window y", 0, &ok);
1211                 if (ok)
1212                         move(x, y);
1213                 QValueList<int> sizes = configSettings->readSizes("/split", &ok);
1214                 if (ok)
1215                         split->setSizes(sizes);
1216                 configSettings->endGroup();
1217                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1218         }
1219 }
1220
1221 void ConfigSearchWindow::saveSettings(void)
1222 {
1223         if (name()) {
1224                 configSettings->beginGroup(name());
1225                 configSettings->writeEntry("/window x", pos().x());
1226                 configSettings->writeEntry("/window y", pos().y());
1227                 configSettings->writeEntry("/window width", size().width());
1228                 configSettings->writeEntry("/window height", size().height());
1229                 configSettings->writeSizes("/split", split->sizes());
1230                 configSettings->endGroup();
1231         }
1232 }
1233
1234 void ConfigSearchWindow::search(void)
1235 {
1236         struct symbol **p;
1237         struct property *prop;
1238         ConfigItem *lastItem = NULL;
1239
1240         free(result);
1241         list->list->clear();
1242         info->clear();
1243
1244         result = sym_re_search(editField->text().latin1());
1245         if (!result)
1246                 return;
1247         for (p = result; *p; p++) {
1248                 for_all_prompts((*p), prop)
1249                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1250                                                   menu_is_visible(prop->menu));
1251         }
1252 }
1253
1254 /*
1255  * Construct the complete config widget
1256  */
1257 ConfigMainWindow::ConfigMainWindow(void)
1258         : searchWindow(0)
1259 {
1260         QMenuBar* menu;
1261         bool ok;
1262         int x, y, width, height;
1263         char title[256];
1264
1265         QDesktopWidget *d = configApp->desktop();
1266         snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"),
1267                 getenv("KERNELVERSION"));
1268         setCaption(title);
1269
1270         width = configSettings->readNumEntry("/window width", d->width() - 64);
1271         height = configSettings->readNumEntry("/window height", d->height() - 64);
1272         resize(width, height);
1273         x = configSettings->readNumEntry("/window x", 0, &ok);
1274         if (ok)
1275                 y = configSettings->readNumEntry("/window y", 0, &ok);
1276         if (ok)
1277                 move(x, y);
1278
1279         split1 = new QSplitter(this);
1280         split1->setOrientation(Qt::Horizontal);
1281         setCentralWidget(split1);
1282
1283         menuView = new ConfigView(split1, "menu");
1284         menuList = menuView->list;
1285
1286         split2 = new QSplitter(split1);
1287         split2->setOrientation(Qt::Vertical);
1288
1289         // create config tree
1290         configView = new ConfigView(split2, "config");
1291         configList = configView->list;
1292
1293         helpText = new ConfigInfoView(split2, "help");
1294         helpText->setTextFormat(Qt::RichText);
1295
1296         setTabOrder(configList, helpText);
1297         configList->setFocus();
1298
1299         menu = menuBar();
1300         toolBar = new QToolBar("Tools", this);
1301
1302         backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
1303           connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1304           backAction->setEnabled(FALSE);
1305         QAction *quitAction = new QAction("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
1306           connect(quitAction, SIGNAL(activated()), SLOT(close()));
1307         QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
1308           connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1309         saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
1310           connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1311         conf_set_changed_callback(conf_changed);
1312         // Set saveAction's initial state
1313         conf_changed();
1314         QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
1315           connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1316         QAction *searchAction = new QAction("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
1317           connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1318         QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
1319           connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1320         QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
1321           connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1322         QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
1323           connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1324
1325         QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this);
1326           showNameAction->setToggleAction(TRUE);
1327           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1328           connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1329           showNameAction->setOn(configView->showName());
1330         QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this);
1331           showRangeAction->setToggleAction(TRUE);
1332           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1333           connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1334           showRangeAction->setOn(configList->showRange);
1335         QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this);
1336           showDataAction->setToggleAction(TRUE);
1337           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1338           connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1339           showDataAction->setOn(configList->showData);
1340
1341         QActionGroup *optGroup = new QActionGroup(this);
1342         optGroup->setExclusive(TRUE);
1343         connect(optGroup, SIGNAL(selected(QAction *)), configView,
1344                 SLOT(setOptionMode(QAction *)));
1345         connect(optGroup, SIGNAL(selected(QAction *)), menuView,
1346                 SLOT(setOptionMode(QAction *)));
1347
1348         configView->showNormalAction = new QAction(NULL, _("Show Normal Options"), 0, optGroup);
1349         configView->showAllAction = new QAction(NULL, _("Show All Options"), 0, optGroup);
1350         configView->showPromptAction = new QAction(NULL, _("Show Prompt Options"), 0, optGroup);
1351         configView->showNormalAction->setToggleAction(TRUE);
1352         configView->showNormalAction->setOn(configList->optMode == normalOpt);
1353         configView->showAllAction->setToggleAction(TRUE);
1354         configView->showAllAction->setOn(configList->optMode == allOpt);
1355         configView->showPromptAction->setToggleAction(TRUE);
1356         configView->showPromptAction->setOn(configList->optMode == promptOpt);
1357
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         optGroup->addTo(optionMenu);
1401         optionMenu->insertSeparator();
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(conf_get_configname(), 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(conf_get_configname(), 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 (configList->menuSkip(menu))
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         default:
1529                 break;
1530         }
1531
1532         if (list) {
1533                 item = list->findConfigItem(menu);
1534                 if (item) {
1535                         list->setSelected(item, TRUE);
1536                         list->ensureItemVisible(item);
1537                         list->setFocus();
1538                 }
1539         }
1540 }
1541
1542 void ConfigMainWindow::listFocusChanged(void)
1543 {
1544         if (menuList->mode == menuMode)
1545                 configList->clearSelection();
1546 }
1547
1548 void ConfigMainWindow::goBack(void)
1549 {
1550         ConfigItem* item;
1551
1552         configList->setParentMenu();
1553         if (configList->rootEntry == &rootmenu)
1554                 backAction->setEnabled(FALSE);
1555         item = (ConfigItem*)menuList->selectedItem();
1556         while (item) {
1557                 if (item->menu == configList->rootEntry) {
1558                         menuList->setSelected(item, TRUE);
1559                         break;
1560                 }
1561                 item = (ConfigItem*)item->parent();
1562         }
1563 }
1564
1565 void ConfigMainWindow::showSingleView(void)
1566 {
1567         menuView->hide();
1568         menuList->setRootMenu(0);
1569         configList->mode = singleMode;
1570         if (configList->rootEntry == &rootmenu)
1571                 configList->updateListAll();
1572         else
1573                 configList->setRootMenu(&rootmenu);
1574         configList->setAllOpen(TRUE);
1575         configList->setFocus();
1576 }
1577
1578 void ConfigMainWindow::showSplitView(void)
1579 {
1580         configList->mode = symbolMode;
1581         if (configList->rootEntry == &rootmenu)
1582                 configList->updateListAll();
1583         else
1584                 configList->setRootMenu(&rootmenu);
1585         configList->setAllOpen(TRUE);
1586         configApp->processEvents();
1587         menuList->mode = menuMode;
1588         menuList->setRootMenu(&rootmenu);
1589         menuList->setAllOpen(TRUE);
1590         menuView->show();
1591         menuList->setFocus();
1592 }
1593
1594 void ConfigMainWindow::showFullView(void)
1595 {
1596         menuView->hide();
1597         menuList->setRootMenu(0);
1598         configList->mode = fullMode;
1599         if (configList->rootEntry == &rootmenu)
1600                 configList->updateListAll();
1601         else
1602                 configList->setRootMenu(&rootmenu);
1603         configList->setAllOpen(FALSE);
1604         configList->setFocus();
1605 }
1606
1607 /*
1608  * ask for saving configuration before quitting
1609  * TODO ask only when something changed
1610  */
1611 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1612 {
1613         if (!conf_get_changed()) {
1614                 e->accept();
1615                 return;
1616         }
1617         QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
1618                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1619         mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
1620         mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
1621         mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
1622         switch (mb.exec()) {
1623         case QMessageBox::Yes:
1624                 conf_write(NULL);
1625         case QMessageBox::No:
1626                 e->accept();
1627                 break;
1628         case QMessageBox::Cancel:
1629                 e->ignore();
1630                 break;
1631         }
1632 }
1633
1634 void ConfigMainWindow::showIntro(void)
1635 {
1636         static const QString str = _("Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1637                 "For each option, a blank box indicates the feature is disabled, a check\n"
1638                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1639                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1640                 "If you do not see an option (e.g., a device driver) that you believe\n"
1641                 "should be present, try turning on Show All Options under the Options menu.\n"
1642                 "Although there is no cross reference yet to help you figure out what other\n"
1643                 "options must be enabled to support the option you are interested in, you can\n"
1644                 "still view the help of a grayed-out option.\n\n"
1645                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1646                 "which you can then match by examining other options.\n\n");
1647
1648         QMessageBox::information(this, "qconf", str);
1649 }
1650
1651 void ConfigMainWindow::showAbout(void)
1652 {
1653         static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1654                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
1655
1656         QMessageBox::information(this, "qconf", str);
1657 }
1658
1659 void ConfigMainWindow::saveSettings(void)
1660 {
1661         configSettings->writeEntry("/window x", pos().x());
1662         configSettings->writeEntry("/window y", pos().y());
1663         configSettings->writeEntry("/window width", size().width());
1664         configSettings->writeEntry("/window height", size().height());
1665
1666         QString entry;
1667         switch(configList->mode) {
1668         case singleMode :
1669                 entry = "single";
1670                 break;
1671
1672         case symbolMode :
1673                 entry = "split";
1674                 break;
1675
1676         case fullMode :
1677                 entry = "full";
1678                 break;
1679
1680         default:
1681                 break;
1682         }
1683         configSettings->writeEntry("/listMode", entry);
1684
1685         configSettings->writeSizes("/split1", split1->sizes());
1686         configSettings->writeSizes("/split2", split2->sizes());
1687 }
1688
1689 void ConfigMainWindow::conf_changed(void)
1690 {
1691         if (saveAction)
1692                 saveAction->setEnabled(conf_get_changed());
1693 }
1694
1695 void fixup_rootmenu(struct menu *menu)
1696 {
1697         struct menu *child;
1698         static int menu_cnt = 0;
1699
1700         menu->flags |= MENU_ROOT;
1701         for (child = menu->list; child; child = child->next) {
1702                 if (child->prompt && child->prompt->type == P_MENU) {
1703                         menu_cnt++;
1704                         fixup_rootmenu(child);
1705                         menu_cnt--;
1706                 } else if (!menu_cnt)
1707                         fixup_rootmenu(child);
1708         }
1709 }
1710
1711 static const char *progname;
1712
1713 static void usage(void)
1714 {
1715         printf(_("%s <config>\n"), progname);
1716         exit(0);
1717 }
1718
1719 int main(int ac, char** av)
1720 {
1721         ConfigMainWindow* v;
1722         const char *name;
1723
1724         bindtextdomain(PACKAGE, LOCALEDIR);
1725         textdomain(PACKAGE);
1726
1727 #ifndef LKC_DIRECT_LINK
1728         kconfig_load();
1729 #endif
1730
1731         progname = av[0];
1732         configApp = new QApplication(ac, av);
1733         if (ac > 1 && av[1][0] == '-') {
1734                 switch (av[1][1]) {
1735                 case 'h':
1736                 case '?':
1737                         usage();
1738                 }
1739                 name = av[2];
1740         } else
1741                 name = av[1];
1742         if (!name)
1743                 usage();
1744
1745         conf_parse(name);
1746         fixup_rootmenu(&rootmenu);
1747         conf_read(NULL);
1748         //zconfdump(stdout);
1749
1750         configSettings = new ConfigSettings();
1751         configSettings->beginGroup("/kconfig/qconf");
1752         v = new ConfigMainWindow();
1753
1754         //zconfdump(stdout);
1755         configApp->setMainWidget(v);
1756         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1757         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1758         v->show();
1759         configApp->exec();
1760
1761         configSettings->endGroup();
1762         delete configSettings;
1763
1764         return 0;
1765 }