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