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