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