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