Merge tag 'sched-urgent-2020-08-15' of git://git.kernel.org/pub/scm/linux/kernel...
[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(setOn(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(setOn(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(setOn(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
1017 void ConfigInfoView::saveSettings(void)
1018 {
1019         if (!objectName().isEmpty()) {
1020                 configSettings->beginGroup(objectName());
1021                 configSettings->setValue("/showDebug", showDebug());
1022                 configSettings->endGroup();
1023         }
1024 }
1025
1026 void ConfigInfoView::setShowDebug(bool b)
1027 {
1028         if (_showDebug != b) {
1029                 _showDebug = b;
1030                 if (_menu)
1031                         menuInfo();
1032                 else if (sym)
1033                         symbolInfo();
1034                 emit showDebugChanged(b);
1035         }
1036 }
1037
1038 void ConfigInfoView::setInfo(struct menu *m)
1039 {
1040         if (_menu == m)
1041                 return;
1042         _menu = m;
1043         sym = NULL;
1044         if (!_menu)
1045                 clear();
1046         else
1047                 menuInfo();
1048 }
1049
1050 void ConfigInfoView::symbolInfo(void)
1051 {
1052         QString str;
1053
1054         str += "<big>Symbol: <b>";
1055         str += print_filter(sym->name);
1056         str += "</b></big><br><br>value: ";
1057         str += print_filter(sym_get_string_value(sym));
1058         str += "<br>visibility: ";
1059         str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1060         str += "<br>";
1061         str += debug_info(sym);
1062
1063         setText(str);
1064 }
1065
1066 void ConfigInfoView::menuInfo(void)
1067 {
1068         struct symbol* sym;
1069         QString head, debug, help;
1070
1071         sym = _menu->sym;
1072         if (sym) {
1073                 if (_menu->prompt) {
1074                         head += "<big><b>";
1075                         head += print_filter(_menu->prompt->text);
1076                         head += "</b></big>";
1077                         if (sym->name) {
1078                                 head += " (";
1079                                 if (showDebug())
1080                                         head += QString().sprintf("<a href=\"s%s\">", sym->name);
1081                                 head += print_filter(sym->name);
1082                                 if (showDebug())
1083                                         head += "</a>";
1084                                 head += ")";
1085                         }
1086                 } else if (sym->name) {
1087                         head += "<big><b>";
1088                         if (showDebug())
1089                                 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1090                         head += print_filter(sym->name);
1091                         if (showDebug())
1092                                 head += "</a>";
1093                         head += "</b></big>";
1094                 }
1095                 head += "<br><br>";
1096
1097                 if (showDebug())
1098                         debug = debug_info(sym);
1099
1100                 struct gstr help_gstr = str_new();
1101                 menu_get_ext_help(_menu, &help_gstr);
1102                 help = print_filter(str_get(&help_gstr));
1103                 str_free(&help_gstr);
1104         } else if (_menu->prompt) {
1105                 head += "<big><b>";
1106                 head += print_filter(_menu->prompt->text);
1107                 head += "</b></big><br><br>";
1108                 if (showDebug()) {
1109                         if (_menu->prompt->visible.expr) {
1110                                 debug += "&nbsp;&nbsp;dep: ";
1111                                 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1112                                 debug += "<br><br>";
1113                         }
1114                 }
1115         }
1116         if (showDebug())
1117                 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1118
1119         setText(head + debug + help);
1120 }
1121
1122 QString ConfigInfoView::debug_info(struct symbol *sym)
1123 {
1124         QString debug;
1125
1126         debug += "type: ";
1127         debug += print_filter(sym_type_name(sym->type));
1128         if (sym_is_choice(sym))
1129                 debug += " (choice)";
1130         debug += "<br>";
1131         if (sym->rev_dep.expr) {
1132                 debug += "reverse dep: ";
1133                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1134                 debug += "<br>";
1135         }
1136         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1137                 switch (prop->type) {
1138                 case P_PROMPT:
1139                 case P_MENU:
1140                         debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1141                         debug += print_filter(prop->text);
1142                         debug += "</a><br>";
1143                         break;
1144                 case P_DEFAULT:
1145                 case P_SELECT:
1146                 case P_RANGE:
1147                 case P_COMMENT:
1148                 case P_IMPLY:
1149                 case P_SYMBOL:
1150                         debug += prop_get_type_name(prop->type);
1151                         debug += ": ";
1152                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1153                         debug += "<br>";
1154                         break;
1155                 case P_CHOICE:
1156                         if (sym_is_choice(sym)) {
1157                                 debug += "choice: ";
1158                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1159                                 debug += "<br>";
1160                         }
1161                         break;
1162                 default:
1163                         debug += "unknown property: ";
1164                         debug += prop_get_type_name(prop->type);
1165                         debug += "<br>";
1166                 }
1167                 if (prop->visible.expr) {
1168                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1169                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1170                         debug += "<br>";
1171                 }
1172         }
1173         debug += "<br>";
1174
1175         return debug;
1176 }
1177
1178 QString ConfigInfoView::print_filter(const QString &str)
1179 {
1180         QRegExp re("[<>&\"\\n]");
1181         QString res = str;
1182         for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1183                 switch (res[i].toLatin1()) {
1184                 case '<':
1185                         res.replace(i, 1, "&lt;");
1186                         i += 4;
1187                         break;
1188                 case '>':
1189                         res.replace(i, 1, "&gt;");
1190                         i += 4;
1191                         break;
1192                 case '&':
1193                         res.replace(i, 1, "&amp;");
1194                         i += 5;
1195                         break;
1196                 case '"':
1197                         res.replace(i, 1, "&quot;");
1198                         i += 6;
1199                         break;
1200                 case '\n':
1201                         res.replace(i, 1, "<br>");
1202                         i += 4;
1203                         break;
1204                 }
1205         }
1206         return res;
1207 }
1208
1209 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1210 {
1211         QString* text = reinterpret_cast<QString*>(data);
1212         QString str2 = print_filter(str);
1213
1214         if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1215                 *text += QString().sprintf("<a href=\"s%s\">", sym->name);
1216                 *text += str2;
1217                 *text += "</a>";
1218         } else
1219                 *text += str2;
1220 }
1221
1222 void ConfigInfoView::clicked(const QUrl &url)
1223 {
1224         QByteArray str = url.toEncoded();
1225         const std::size_t count = str.size();
1226         char *data = new char[count + 1];
1227         struct symbol **result;
1228         struct menu *m = NULL;
1229
1230         if (count < 1) {
1231                 qInfo() << "Clicked link is empty";
1232                 delete[] data;
1233                 return;
1234         }
1235
1236         memcpy(data, str.constData(), count);
1237         data[count] = '\0';
1238
1239         /* Seek for exact match */
1240         data[0] = '^';
1241         strcat(data, "$");
1242         result = sym_re_search(data);
1243         if (!result) {
1244                 qInfo() << "Clicked symbol is invalid:" << data;
1245                 delete[] data;
1246                 return;
1247         }
1248
1249         sym = *result;
1250
1251         /* Seek for the menu which holds the symbol */
1252         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1253                     if (prop->type != P_PROMPT && prop->type != P_MENU)
1254                             continue;
1255                     m = prop->menu;
1256                     break;
1257         }
1258
1259         if (!m) {
1260                 /* Symbol is not visible as a menu */
1261                 symbolInfo();
1262                 emit showDebugChanged(true);
1263         } else {
1264                 emit menuSelected(m);
1265         }
1266
1267         free(result);
1268         delete data;
1269 }
1270
1271 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1272 {
1273         QMenu* popup = Parent::createStandardContextMenu(pos);
1274         QAction* action = new QAction("Show Debug Info", popup);
1275
1276         action->setCheckable(true);
1277         connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1278         connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1279         action->setChecked(showDebug());
1280         popup->addSeparator();
1281         popup->addAction(action);
1282         return popup;
1283 }
1284
1285 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1286 {
1287         Parent::contextMenuEvent(e);
1288 }
1289
1290 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1291         : Parent(parent), result(NULL)
1292 {
1293         setObjectName("search");
1294         setWindowTitle("Search Config");
1295
1296         QVBoxLayout* layout1 = new QVBoxLayout(this);
1297         layout1->setContentsMargins(11, 11, 11, 11);
1298         layout1->setSpacing(6);
1299
1300         QHBoxLayout* layout2 = new QHBoxLayout();
1301         layout2->setContentsMargins(0, 0, 0, 0);
1302         layout2->setSpacing(6);
1303         layout2->addWidget(new QLabel("Find:", this));
1304         editField = new QLineEdit(this);
1305         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1306         layout2->addWidget(editField);
1307         searchButton = new QPushButton("Search", this);
1308         searchButton->setAutoDefault(false);
1309         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1310         layout2->addWidget(searchButton);
1311         layout1->addLayout(layout2);
1312
1313         split = new QSplitter(this);
1314         split->setOrientation(Qt::Vertical);
1315         list = new ConfigView(split, "search");
1316         list->list->mode = listMode;
1317         info = new ConfigInfoView(split, "search");
1318         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1319                 info, SLOT(setInfo(struct menu *)));
1320         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1321                 parent, SLOT(setMenuLink(struct menu *)));
1322
1323         layout1->addWidget(split);
1324
1325         QVariant x, y;
1326         int width, height;
1327         bool ok;
1328
1329         configSettings->beginGroup("search");
1330         width = configSettings->value("/window width", parent->width() / 2).toInt();
1331         height = configSettings->value("/window height", parent->height() / 2).toInt();
1332         resize(width, height);
1333         x = configSettings->value("/window x");
1334         y = configSettings->value("/window y");
1335         if (x.isValid() && y.isValid())
1336                 move(x.toInt(), y.toInt());
1337         QList<int> sizes = configSettings->readSizes("/split", &ok);
1338         if (ok)
1339                 split->setSizes(sizes);
1340         configSettings->endGroup();
1341         connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1342 }
1343
1344 void ConfigSearchWindow::saveSettings(void)
1345 {
1346         if (!objectName().isEmpty()) {
1347                 configSettings->beginGroup(objectName());
1348                 configSettings->setValue("/window x", pos().x());
1349                 configSettings->setValue("/window y", pos().y());
1350                 configSettings->setValue("/window width", size().width());
1351                 configSettings->setValue("/window height", size().height());
1352                 configSettings->writeSizes("/split", split->sizes());
1353                 configSettings->endGroup();
1354         }
1355 }
1356
1357 void ConfigSearchWindow::search(void)
1358 {
1359         struct symbol **p;
1360         struct property *prop;
1361         ConfigItem *lastItem = NULL;
1362
1363         free(result);
1364         list->list->clear();
1365         info->clear();
1366
1367         result = sym_re_search(editField->text().toLatin1());
1368         if (!result)
1369                 return;
1370         for (p = result; *p; p++) {
1371                 for_all_prompts((*p), prop)
1372                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1373                                                   menu_is_visible(prop->menu));
1374         }
1375 }
1376
1377 /*
1378  * Construct the complete config widget
1379  */
1380 ConfigMainWindow::ConfigMainWindow(void)
1381         : searchWindow(0)
1382 {
1383         bool ok = true;
1384         QVariant x, y;
1385         int width, height;
1386         char title[256];
1387
1388         QDesktopWidget *d = configApp->desktop();
1389         snprintf(title, sizeof(title), "%s%s",
1390                 rootmenu.prompt->text,
1391                 ""
1392                 );
1393         setWindowTitle(title);
1394
1395         width = configSettings->value("/window width", d->width() - 64).toInt();
1396         height = configSettings->value("/window height", d->height() - 64).toInt();
1397         resize(width, height);
1398         x = configSettings->value("/window x");
1399         y = configSettings->value("/window y");
1400         if ((x.isValid())&&(y.isValid()))
1401                 move(x.toInt(), y.toInt());
1402
1403         // set up icons
1404         ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
1405         ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
1406         ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
1407         ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
1408         ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
1409         ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
1410         ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
1411
1412         QWidget *widget = new QWidget(this);
1413         QVBoxLayout *layout = new QVBoxLayout(widget);
1414         setCentralWidget(widget);
1415
1416         split1 = new QSplitter(widget);
1417         split1->setOrientation(Qt::Horizontal);
1418         split1->setChildrenCollapsible(false);
1419
1420         menuView = new ConfigView(widget, "menu");
1421         menuList = menuView->list;
1422
1423         split2 = new QSplitter(widget);
1424         split2->setChildrenCollapsible(false);
1425         split2->setOrientation(Qt::Vertical);
1426
1427         // create config tree
1428         configView = new ConfigView(widget, "config");
1429         configList = configView->list;
1430
1431         helpText = new ConfigInfoView(widget, "help");
1432
1433         layout->addWidget(split2);
1434         split2->addWidget(split1);
1435         split1->addWidget(configView);
1436         split1->addWidget(menuView);
1437         split2->addWidget(helpText);
1438
1439         setTabOrder(configList, helpText);
1440         configList->setFocus();
1441
1442         backAction = new QAction(QPixmap(xpm_back), "Back", this);
1443         connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1444
1445         QAction *quitAction = new QAction("&Quit", this);
1446         quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1447         connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1448
1449         QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1450         loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1451         connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1452
1453         saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1454         saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1455         connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1456
1457         conf_set_changed_callback(conf_changed);
1458
1459         // Set saveAction's initial state
1460         conf_changed();
1461         configname = xstrdup(conf_get_configname());
1462
1463         QAction *saveAsAction = new QAction("Save &As...", this);
1464           connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1465         QAction *searchAction = new QAction("&Find", this);
1466         searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1467           connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1468         singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1469         singleViewAction->setCheckable(true);
1470           connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1471         splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1472         splitViewAction->setCheckable(true);
1473           connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1474         fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1475         fullViewAction->setCheckable(true);
1476           connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1477
1478         QAction *showNameAction = new QAction("Show Name", this);
1479           showNameAction->setCheckable(true);
1480           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1481           showNameAction->setChecked(configView->showName());
1482         QAction *showRangeAction = new QAction("Show Range", this);
1483           showRangeAction->setCheckable(true);
1484           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1485         QAction *showDataAction = new QAction("Show Data", this);
1486           showDataAction->setCheckable(true);
1487           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1488
1489         QActionGroup *optGroup = new QActionGroup(this);
1490         optGroup->setExclusive(true);
1491         connect(optGroup, SIGNAL(triggered(QAction*)), configList,
1492                 SLOT(setOptionMode(QAction *)));
1493         connect(optGroup, SIGNAL(triggered(QAction *)), menuList,
1494                 SLOT(setOptionMode(QAction *)));
1495
1496         ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
1497         ConfigList::showNormalAction->setCheckable(true);
1498         ConfigList::showAllAction = new QAction("Show All Options", optGroup);
1499         ConfigList::showAllAction->setCheckable(true);
1500         ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
1501         ConfigList::showPromptAction->setCheckable(true);
1502
1503         QAction *showDebugAction = new QAction("Show Debug Info", this);
1504           showDebugAction->setCheckable(true);
1505           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1506           showDebugAction->setChecked(helpText->showDebug());
1507
1508         QAction *showIntroAction = new QAction("Introduction", this);
1509           connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1510         QAction *showAboutAction = new QAction("About", this);
1511           connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1512
1513         // init tool bar
1514         QToolBar *toolBar = addToolBar("Tools");
1515         toolBar->addAction(backAction);
1516         toolBar->addSeparator();
1517         toolBar->addAction(loadAction);
1518         toolBar->addAction(saveAction);
1519         toolBar->addSeparator();
1520         toolBar->addAction(singleViewAction);
1521         toolBar->addAction(splitViewAction);
1522         toolBar->addAction(fullViewAction);
1523
1524         // create file menu
1525         QMenu *menu = menuBar()->addMenu("&File");
1526         menu->addAction(loadAction);
1527         menu->addAction(saveAction);
1528         menu->addAction(saveAsAction);
1529         menu->addSeparator();
1530         menu->addAction(quitAction);
1531
1532         // create edit menu
1533         menu = menuBar()->addMenu("&Edit");
1534         menu->addAction(searchAction);
1535
1536         // create options menu
1537         menu = menuBar()->addMenu("&Option");
1538         menu->addAction(showNameAction);
1539         menu->addAction(showRangeAction);
1540         menu->addAction(showDataAction);
1541         menu->addSeparator();
1542         menu->addActions(optGroup->actions());
1543         menu->addSeparator();
1544         menu->addAction(showDebugAction);
1545
1546         // create help menu
1547         menu = menuBar()->addMenu("&Help");
1548         menu->addAction(showIntroAction);
1549         menu->addAction(showAboutAction);
1550
1551         connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1552                  helpText, SLOT (clicked (const QUrl &)) );
1553
1554         connect(configList, SIGNAL(menuChanged(struct menu *)),
1555                 helpText, SLOT(setInfo(struct menu *)));
1556         connect(configList, SIGNAL(menuSelected(struct menu *)),
1557                 SLOT(changeMenu(struct menu *)));
1558         connect(configList, SIGNAL(itemSelected(struct menu *)),
1559                 SLOT(changeItens(struct menu *)));
1560         connect(configList, SIGNAL(parentSelected()),
1561                 SLOT(goBack()));
1562         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1563                 helpText, SLOT(setInfo(struct menu *)));
1564         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1565                 SLOT(changeMenu(struct menu *)));
1566
1567         connect(configList, SIGNAL(gotFocus(struct menu *)),
1568                 helpText, SLOT(setInfo(struct menu *)));
1569         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1570                 helpText, SLOT(setInfo(struct menu *)));
1571         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1572                 SLOT(listFocusChanged(void)));
1573         connect(helpText, SIGNAL(menuSelected(struct menu *)),
1574                 SLOT(setMenuLink(struct menu *)));
1575
1576         QString listMode = configSettings->value("/listMode", "symbol").toString();
1577         if (listMode == "single")
1578                 showSingleView();
1579         else if (listMode == "full")
1580                 showFullView();
1581         else /*if (listMode == "split")*/
1582                 showSplitView();
1583
1584         // UI setup done, restore splitter positions
1585         QList<int> sizes = configSettings->readSizes("/split1", &ok);
1586         if (ok)
1587                 split1->setSizes(sizes);
1588
1589         sizes = configSettings->readSizes("/split2", &ok);
1590         if (ok)
1591                 split2->setSizes(sizes);
1592 }
1593
1594 void ConfigMainWindow::loadConfig(void)
1595 {
1596         QString str;
1597         QByteArray ba;
1598         const char *name;
1599
1600         str = QFileDialog::getOpenFileName(this, "", configname);
1601         if (str.isNull())
1602                 return;
1603
1604         ba = str.toLocal8Bit();
1605         name = ba.data();
1606
1607         if (conf_read(name))
1608                 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1609
1610         free(configname);
1611         configname = xstrdup(name);
1612
1613         ConfigView::updateListAll();
1614 }
1615
1616 bool ConfigMainWindow::saveConfig(void)
1617 {
1618         if (conf_write(configname)) {
1619                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1620                 return false;
1621         }
1622         conf_write_autoconf(0);
1623
1624         return true;
1625 }
1626
1627 void ConfigMainWindow::saveConfigAs(void)
1628 {
1629         QString str;
1630         QByteArray ba;
1631         const char *name;
1632
1633         str = QFileDialog::getSaveFileName(this, "", configname);
1634         if (str.isNull())
1635                 return;
1636
1637         ba = str.toLocal8Bit();
1638         name = ba.data();
1639
1640         if (conf_write(name)) {
1641                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1642         }
1643         conf_write_autoconf(0);
1644
1645         free(configname);
1646         configname = xstrdup(name);
1647 }
1648
1649 void ConfigMainWindow::searchConfig(void)
1650 {
1651         if (!searchWindow)
1652                 searchWindow = new ConfigSearchWindow(this);
1653         searchWindow->show();
1654 }
1655
1656 void ConfigMainWindow::changeItens(struct menu *menu)
1657 {
1658         configList->setRootMenu(menu);
1659 }
1660
1661 void ConfigMainWindow::changeMenu(struct menu *menu)
1662 {
1663         menuList->setRootMenu(menu);
1664 }
1665
1666 void ConfigMainWindow::setMenuLink(struct menu *menu)
1667 {
1668         struct menu *parent;
1669         ConfigList* list = NULL;
1670         ConfigItem* item;
1671
1672         if (configList->menuSkip(menu))
1673                 return;
1674
1675         switch (configList->mode) {
1676         case singleMode:
1677                 list = configList;
1678                 parent = menu_get_parent_menu(menu);
1679                 if (!parent)
1680                         return;
1681                 list->setRootMenu(parent);
1682                 break;
1683         case menuMode:
1684                 if (menu->flags & MENU_ROOT) {
1685                         menuList->setRootMenu(menu);
1686                         configList->clearSelection();
1687                         list = configList;
1688                 } else {
1689                         parent = menu_get_parent_menu(menu->parent);
1690                         if (!parent)
1691                                 return;
1692
1693                         /* Select the config view */
1694                         item = configList->findConfigItem(parent);
1695                         if (item) {
1696                                 configList->setSelected(item, true);
1697                                 configList->scrollToItem(item);
1698                         }
1699
1700                         menuList->setRootMenu(parent);
1701                         menuList->clearSelection();
1702                         list = menuList;
1703                 }
1704                 break;
1705         case fullMode:
1706                 list = configList;
1707                 break;
1708         default:
1709                 break;
1710         }
1711
1712         if (list) {
1713                 item = list->findConfigItem(menu);
1714                 if (item) {
1715                         list->setSelected(item, true);
1716                         list->scrollToItem(item);
1717                         list->setFocus();
1718                         helpText->setInfo(menu);
1719                 }
1720         }
1721 }
1722
1723 void ConfigMainWindow::listFocusChanged(void)
1724 {
1725         if (menuList->mode == menuMode)
1726                 configList->clearSelection();
1727 }
1728
1729 void ConfigMainWindow::goBack(void)
1730 {
1731         if (configList->rootEntry == &rootmenu)
1732                 return;
1733
1734         configList->setParentMenu();
1735 }
1736
1737 void ConfigMainWindow::showSingleView(void)
1738 {
1739         singleViewAction->setEnabled(false);
1740         singleViewAction->setChecked(true);
1741         splitViewAction->setEnabled(true);
1742         splitViewAction->setChecked(false);
1743         fullViewAction->setEnabled(true);
1744         fullViewAction->setChecked(false);
1745
1746         backAction->setEnabled(true);
1747
1748         menuView->hide();
1749         menuList->setRootMenu(0);
1750         configList->mode = singleMode;
1751         if (configList->rootEntry == &rootmenu)
1752                 configList->updateListAll();
1753         else
1754                 configList->setRootMenu(&rootmenu);
1755         configList->setFocus();
1756 }
1757
1758 void ConfigMainWindow::showSplitView(void)
1759 {
1760         singleViewAction->setEnabled(true);
1761         singleViewAction->setChecked(false);
1762         splitViewAction->setEnabled(false);
1763         splitViewAction->setChecked(true);
1764         fullViewAction->setEnabled(true);
1765         fullViewAction->setChecked(false);
1766
1767         backAction->setEnabled(false);
1768
1769         configList->mode = menuMode;
1770         if (configList->rootEntry == &rootmenu)
1771                 configList->updateListAll();
1772         else
1773                 configList->setRootMenu(&rootmenu);
1774         configList->setAllOpen(true);
1775         configApp->processEvents();
1776         menuList->mode = symbolMode;
1777         menuList->setRootMenu(&rootmenu);
1778         menuList->setAllOpen(true);
1779         menuView->show();
1780         menuList->setFocus();
1781 }
1782
1783 void ConfigMainWindow::showFullView(void)
1784 {
1785         singleViewAction->setEnabled(true);
1786         singleViewAction->setChecked(false);
1787         splitViewAction->setEnabled(true);
1788         splitViewAction->setChecked(false);
1789         fullViewAction->setEnabled(false);
1790         fullViewAction->setChecked(true);
1791
1792         backAction->setEnabled(false);
1793
1794         menuView->hide();
1795         menuList->setRootMenu(0);
1796         configList->mode = fullMode;
1797         if (configList->rootEntry == &rootmenu)
1798                 configList->updateListAll();
1799         else
1800                 configList->setRootMenu(&rootmenu);
1801         configList->setFocus();
1802 }
1803
1804 /*
1805  * ask for saving configuration before quitting
1806  */
1807 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1808 {
1809         if (!conf_get_changed()) {
1810                 e->accept();
1811                 return;
1812         }
1813         QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1814                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1815         mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1816         mb.setButtonText(QMessageBox::No, "&Discard Changes");
1817         mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1818         switch (mb.exec()) {
1819         case QMessageBox::Yes:
1820                 if (saveConfig())
1821                         e->accept();
1822                 else
1823                         e->ignore();
1824                 break;
1825         case QMessageBox::No:
1826                 e->accept();
1827                 break;
1828         case QMessageBox::Cancel:
1829                 e->ignore();
1830                 break;
1831         }
1832 }
1833
1834 void ConfigMainWindow::showIntro(void)
1835 {
1836         static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1837                 "For each option, a blank box indicates the feature is disabled, a check\n"
1838                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1839                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1840                 "If you do not see an option (e.g., a device driver) that you believe\n"
1841                 "should be present, try turning on Show All Options under the Options menu.\n"
1842                 "Although there is no cross reference yet to help you figure out what other\n"
1843                 "options must be enabled to support the option you are interested in, you can\n"
1844                 "still view the help of a grayed-out option.\n\n"
1845                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1846                 "which you can then match by examining other options.\n\n";
1847
1848         QMessageBox::information(this, "qconf", str);
1849 }
1850
1851 void ConfigMainWindow::showAbout(void)
1852 {
1853         static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1854                 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1855                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1856
1857         QMessageBox::information(this, "qconf", str);
1858 }
1859
1860 void ConfigMainWindow::saveSettings(void)
1861 {
1862         configSettings->setValue("/window x", pos().x());
1863         configSettings->setValue("/window y", pos().y());
1864         configSettings->setValue("/window width", size().width());
1865         configSettings->setValue("/window height", size().height());
1866
1867         QString entry;
1868         switch(configList->mode) {
1869         case singleMode :
1870                 entry = "single";
1871                 break;
1872
1873         case symbolMode :
1874                 entry = "split";
1875                 break;
1876
1877         case fullMode :
1878                 entry = "full";
1879                 break;
1880
1881         default:
1882                 break;
1883         }
1884         configSettings->setValue("/listMode", entry);
1885
1886         configSettings->writeSizes("/split1", split1->sizes());
1887         configSettings->writeSizes("/split2", split2->sizes());
1888 }
1889
1890 void ConfigMainWindow::conf_changed(void)
1891 {
1892         if (saveAction)
1893                 saveAction->setEnabled(conf_get_changed());
1894 }
1895
1896 void fixup_rootmenu(struct menu *menu)
1897 {
1898         struct menu *child;
1899         static int menu_cnt = 0;
1900
1901         menu->flags |= MENU_ROOT;
1902         for (child = menu->list; child; child = child->next) {
1903                 if (child->prompt && child->prompt->type == P_MENU) {
1904                         menu_cnt++;
1905                         fixup_rootmenu(child);
1906                         menu_cnt--;
1907                 } else if (!menu_cnt)
1908                         fixup_rootmenu(child);
1909         }
1910 }
1911
1912 static const char *progname;
1913
1914 static void usage(void)
1915 {
1916         printf("%s [-s] <config>\n", progname);
1917         exit(0);
1918 }
1919
1920 int main(int ac, char** av)
1921 {
1922         ConfigMainWindow* v;
1923         const char *name;
1924
1925         progname = av[0];
1926         configApp = new QApplication(ac, av);
1927         if (ac > 1 && av[1][0] == '-') {
1928                 switch (av[1][1]) {
1929                 case 's':
1930                         conf_set_message_callback(NULL);
1931                         break;
1932                 case 'h':
1933                 case '?':
1934                         usage();
1935                 }
1936                 name = av[2];
1937         } else
1938                 name = av[1];
1939         if (!name)
1940                 usage();
1941
1942         conf_parse(name);
1943         fixup_rootmenu(&rootmenu);
1944         conf_read(NULL);
1945         //zconfdump(stdout);
1946
1947         configSettings = new ConfigSettings();
1948         configSettings->beginGroup("/kconfig/qconf");
1949         v = new ConfigMainWindow();
1950
1951         //zconfdump(stdout);
1952         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1953         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1954         v->show();
1955         configApp->exec();
1956
1957         configSettings->endGroup();
1958         delete configSettings;
1959         delete v;
1960         delete configApp;
1961
1962         return 0;
1963 }