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