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