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