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