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