xref: /linux/scripts/kconfig/qconf.cc (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
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 
35 ConfigSettings::ConfigSettings()
36 	: QSettings("kernel.org", "qconf")
37 {
38 	beginGroup("/kconfig/qconf");
39 }
40 
41 ConfigSettings::~ConfigSettings()
42 {
43 	endGroup();
44 }
45 
46 /**
47  * Reads a list of integer values from the application settings.
48  */
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  */
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  */
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 
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  */
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  */
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 
258 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 
276 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 
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 
348 ConfigList::~ConfigList()
349 {
350 	allLists.removeOne(this);
351 }
352 
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 
364 void ConfigList::reinit(void)
365 {
366 	hideColumn(nameColIdx);
367 
368 	if (showName)
369 		showColumn(nameColIdx);
370 
371 	updateListAll();
372 }
373 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 << "&nbsp;&nbsp;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 
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 << "&nbsp;&nbsp;&nbsp;&nbsp;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 
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['<'] = "&lt;";
1119 	patterns['>'] = "&gt;";
1120 	patterns['&'] = "&amp;";
1121 	patterns['"'] = "&quot;";
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 
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 
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 
1163 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1164 {
1165 	contextMenu->popup(event->globalPos());
1166 	event->accept();
1167 }
1168 
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 
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 
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  */
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 
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 
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 
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 
1532 void ConfigMainWindow::searchConfig(void)
1533 {
1534 	if (!searchWindow)
1535 		searchWindow = new ConfigSearchWindow(this);
1536 	searchWindow->show();
1537 }
1538 
1539 void ConfigMainWindow::changeItens(struct menu *menu)
1540 {
1541 	configList->setRootMenu(menu);
1542 }
1543 
1544 void ConfigMainWindow::changeMenu(struct menu *menu)
1545 {
1546 	menuList->setRootMenu(menu);
1547 }
1548 
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 
1606 void ConfigMainWindow::listFocusChanged(void)
1607 {
1608 	if (menuList->mode == menuMode)
1609 		configList->clearSelection();
1610 }
1611 
1612 void ConfigMainWindow::goBack(void)
1613 {
1614 	configList->setParentMenu();
1615 }
1616 
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 
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 
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  */
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 
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 
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 
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 
1792 void ConfigMainWindow::conf_changed(bool dirty)
1793 {
1794 	if (saveAction)
1795 		saveAction->setEnabled(dirty);
1796 }
1797 
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 
1816 static void usage(void)
1817 {
1818 	printf("%s [-s] <config>\n", progname);
1819 	exit(0);
1820 }
1821 
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