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