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