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