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 }
41
42 /**
43 * Reads a list of integer values from the application settings.
44 */
readSizes(const QString & key,bool * ok)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 */
writeSizes(const QString & key,const QList<int> & value)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 */
updateMenu(void)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
testUpdateMenu(void)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 */
init(void)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 */
~ConfigItem(void)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
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & index) const246 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
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const264 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
ConfigList(QWidget * parent,const char * name)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
~ConfigList()336 ConfigList::~ConfigList()
337 {
338 allLists.removeOne(this);
339 }
340
menuSkip(struct menu * menu)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
reinit(void)352 void ConfigList::reinit(void)
353 {
354 hideColumn(nameColIdx);
355
356 if (showName)
357 showColumn(nameColIdx);
358
359 updateListAll();
360 }
361
setOptionMode(QAction * action)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
saveSettings(void)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
findConfigItem(struct menu * menu)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
updateSelection(void)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
updateList()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
updateListForAll()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
updateListAllForAll()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
setValue(ConfigItem * item,tristate val)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
changeValue(ConfigItem * item)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
setRootMenu(struct menu * menu)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
setParentMenu(void)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 */
updateMenuList(ConfigItem * parent,struct menu * menu)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
updateMenuList(struct menu * menu)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
keyPressEvent(QKeyEvent * ev)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
mouseReleaseEvent(QMouseEvent * e)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
mouseDoubleClickEvent(QMouseEvent * e)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
focusInEvent(QFocusEvent * e)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
contextMenuEvent(QContextMenuEvent * e)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
setShowName(bool on)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
setAllOpen(bool open)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
ConfigInfoView(QWidget * parent,const char * name)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
saveSettings(void)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
setShowDebug(bool b)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
setInfo(struct menu * m)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
symbolInfo(void)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
menuInfo(void)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 << " 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
debug_info(struct symbol * sym)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 << " 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
print_filter(const QString & str)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['<'] = "<";
1107 patterns['>'] = ">";
1108 patterns['&'] = "&";
1109 patterns['"'] = """;
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
expr_print_help(void * data,struct symbol * sym,const char * str)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
clicked(const QUrl & url)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
contextMenuEvent(QContextMenuEvent * event)1151 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1152 {
1153 contextMenu->popup(event->globalPos());
1154 event->accept();
1155 }
1156
ConfigSearchWindow(ConfigMainWindow * parent)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
saveSettings(void)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
search(void)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 */
ConfigMainWindow(void)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
loadConfig(void)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
saveConfig(void)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
saveConfigAs(void)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
searchConfig(void)1506 void ConfigMainWindow::searchConfig(void)
1507 {
1508 if (!searchWindow)
1509 searchWindow = new ConfigSearchWindow(this);
1510 searchWindow->show();
1511 }
1512
changeItens(struct menu * menu)1513 void ConfigMainWindow::changeItens(struct menu *menu)
1514 {
1515 configList->setRootMenu(menu);
1516 }
1517
changeMenu(struct menu * menu)1518 void ConfigMainWindow::changeMenu(struct menu *menu)
1519 {
1520 menuList->setRootMenu(menu);
1521 }
1522
setMenuLink(struct menu * menu)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
listFocusChanged(void)1580 void ConfigMainWindow::listFocusChanged(void)
1581 {
1582 if (menuList->mode == menuMode)
1583 configList->clearSelection();
1584 }
1585
goBack(void)1586 void ConfigMainWindow::goBack(void)
1587 {
1588 configList->setParentMenu();
1589 }
1590
showSingleView(void)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
showSplitView(void)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
showFullView(void)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 */
closeEvent(QCloseEvent * e)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
showIntro(void)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
showAbout(void)1724 void ConfigMainWindow::showAbout(void)
1725 {
1726 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1727 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\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
saveSettings(void)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
conf_changed(bool dirty)1766 void ConfigMainWindow::conf_changed(bool dirty)
1767 {
1768 if (saveAction)
1769 saveAction->setEnabled(dirty);
1770 }
1771
fixup_rootmenu(struct menu * menu)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
usage(void)1790 static void usage(void)
1791 {
1792 printf("%s [-s] <config>\n", progname);
1793 exit(0);
1794 }
1795
main(int ac,char ** av)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 }
1839