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