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