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