xref: /openbmc/linux/scripts/kconfig/qconf.cc (revision e953aeaa)
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(setChecked(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(setChecked(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(setChecked(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 	contextMenu = createStandardContextMenu();
1017 	QAction *action = new QAction("Show Debug Info", contextMenu);
1018 
1019 	action->setCheckable(true);
1020 	connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1021 	connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setChecked(bool)));
1022 	action->setChecked(showDebug());
1023 	contextMenu->addSeparator();
1024 	contextMenu->addAction(action);
1025 }
1026 
1027 void ConfigInfoView::saveSettings(void)
1028 {
1029 	if (!objectName().isEmpty()) {
1030 		configSettings->beginGroup(objectName());
1031 		configSettings->setValue("/showDebug", showDebug());
1032 		configSettings->endGroup();
1033 	}
1034 }
1035 
1036 void ConfigInfoView::setShowDebug(bool b)
1037 {
1038 	if (_showDebug != b) {
1039 		_showDebug = b;
1040 		if (_menu)
1041 			menuInfo();
1042 		else if (sym)
1043 			symbolInfo();
1044 		emit showDebugChanged(b);
1045 	}
1046 }
1047 
1048 void ConfigInfoView::setInfo(struct menu *m)
1049 {
1050 	if (_menu == m)
1051 		return;
1052 	_menu = m;
1053 	sym = NULL;
1054 	if (!_menu)
1055 		clear();
1056 	else
1057 		menuInfo();
1058 }
1059 
1060 void ConfigInfoView::symbolInfo(void)
1061 {
1062 	QString str;
1063 
1064 	str += "<big>Symbol: <b>";
1065 	str += print_filter(sym->name);
1066 	str += "</b></big><br><br>value: ";
1067 	str += print_filter(sym_get_string_value(sym));
1068 	str += "<br>visibility: ";
1069 	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1070 	str += "<br>";
1071 	str += debug_info(sym);
1072 
1073 	setText(str);
1074 }
1075 
1076 void ConfigInfoView::menuInfo(void)
1077 {
1078 	struct symbol* sym;
1079 	QString info;
1080 	QTextStream stream(&info);
1081 
1082 	sym = _menu->sym;
1083 	if (sym) {
1084 		if (_menu->prompt) {
1085 			stream << "<big><b>";
1086 			stream << print_filter(_menu->prompt->text);
1087 			stream << "</b></big>";
1088 			if (sym->name) {
1089 				stream << " (";
1090 				if (showDebug())
1091 					stream << "<a href=\"s" << sym->name << "\">";
1092 				stream << print_filter(sym->name);
1093 				if (showDebug())
1094 					stream << "</a>";
1095 				stream << ")";
1096 			}
1097 		} else if (sym->name) {
1098 			stream << "<big><b>";
1099 			if (showDebug())
1100 				stream << "<a href=\"s" << sym->name << "\">";
1101 			stream << print_filter(sym->name);
1102 			if (showDebug())
1103 				stream << "</a>";
1104 			stream << "</b></big>";
1105 		}
1106 		stream << "<br><br>";
1107 
1108 		if (showDebug())
1109 			stream << debug_info(sym);
1110 
1111 	} else if (_menu->prompt) {
1112 		stream << "<big><b>";
1113 		stream << print_filter(_menu->prompt->text);
1114 		stream << "</b></big><br><br>";
1115 		if (showDebug()) {
1116 			if (_menu->prompt->visible.expr) {
1117 				stream << "&nbsp;&nbsp;dep: ";
1118 				expr_print(_menu->prompt->visible.expr,
1119 					   expr_print_help, &stream, E_NONE);
1120 				stream << "<br><br>";
1121 			}
1122 		}
1123 	}
1124 	if (showDebug())
1125 		stream << "defined at " << _menu->file->name << ":"
1126 		       << _menu->lineno << "<br><br>";
1127 
1128 	setText(info);
1129 }
1130 
1131 QString ConfigInfoView::debug_info(struct symbol *sym)
1132 {
1133 	QString debug;
1134 	QTextStream stream(&debug);
1135 
1136 	stream << "type: ";
1137 	stream << print_filter(sym_type_name(sym->type));
1138 	if (sym_is_choice(sym))
1139 		stream << " (choice)";
1140 	debug += "<br>";
1141 	if (sym->rev_dep.expr) {
1142 		stream << "reverse dep: ";
1143 		expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
1144 		stream << "<br>";
1145 	}
1146 	for (struct property *prop = sym->prop; prop; prop = prop->next) {
1147 		switch (prop->type) {
1148 		case P_PROMPT:
1149 		case P_MENU:
1150 			stream << "prompt: <a href=\"m" << sym->name << "\">";
1151 			stream << print_filter(prop->text);
1152 			stream << "</a><br>";
1153 			break;
1154 		case P_DEFAULT:
1155 		case P_SELECT:
1156 		case P_RANGE:
1157 		case P_COMMENT:
1158 		case P_IMPLY:
1159 		case P_SYMBOL:
1160 			stream << prop_get_type_name(prop->type);
1161 			stream << ": ";
1162 			expr_print(prop->expr, expr_print_help,
1163 				   &stream, E_NONE);
1164 			stream << "<br>";
1165 			break;
1166 		case P_CHOICE:
1167 			if (sym_is_choice(sym)) {
1168 				stream << "choice: ";
1169 				expr_print(prop->expr, expr_print_help,
1170 					   &stream, E_NONE);
1171 				stream << "<br>";
1172 			}
1173 			break;
1174 		default:
1175 			stream << "unknown property: ";
1176 			stream << prop_get_type_name(prop->type);
1177 			stream << "<br>";
1178 		}
1179 		if (prop->visible.expr) {
1180 			stream << "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1181 			expr_print(prop->visible.expr, expr_print_help,
1182 				   &stream, E_NONE);
1183 			stream << "<br>";
1184 		}
1185 	}
1186 	stream << "<br>";
1187 
1188 	return debug;
1189 }
1190 
1191 QString ConfigInfoView::print_filter(const QString &str)
1192 {
1193 	QRegExp re("[<>&\"\\n]");
1194 	QString res = str;
1195 	for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1196 		switch (res[i].toLatin1()) {
1197 		case '<':
1198 			res.replace(i, 1, "&lt;");
1199 			i += 4;
1200 			break;
1201 		case '>':
1202 			res.replace(i, 1, "&gt;");
1203 			i += 4;
1204 			break;
1205 		case '&':
1206 			res.replace(i, 1, "&amp;");
1207 			i += 5;
1208 			break;
1209 		case '"':
1210 			res.replace(i, 1, "&quot;");
1211 			i += 6;
1212 			break;
1213 		case '\n':
1214 			res.replace(i, 1, "<br>");
1215 			i += 4;
1216 			break;
1217 		}
1218 	}
1219 	return res;
1220 }
1221 
1222 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1223 {
1224 	QTextStream *stream = reinterpret_cast<QTextStream *>(data);
1225 
1226 	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1227 		*stream << "<a href=\"s" << sym->name << "\">";
1228 		*stream << print_filter(str);
1229 		*stream << "</a>";
1230 	} else {
1231 		*stream << print_filter(str);
1232 	}
1233 }
1234 
1235 void ConfigInfoView::clicked(const QUrl &url)
1236 {
1237 	QByteArray str = url.toEncoded();
1238 	const std::size_t count = str.size();
1239 	char *data = new char[count + 1];
1240 	struct symbol **result;
1241 	struct menu *m = NULL;
1242 
1243 	if (count < 1) {
1244 		delete[] data;
1245 		return;
1246 	}
1247 
1248 	memcpy(data, str.constData(), count);
1249 	data[count] = '\0';
1250 
1251 	/* Seek for exact match */
1252 	data[0] = '^';
1253 	strcat(data, "$");
1254 	result = sym_re_search(data);
1255 	if (!result) {
1256 		delete[] data;
1257 		return;
1258 	}
1259 
1260 	sym = *result;
1261 
1262 	/* Seek for the menu which holds the symbol */
1263 	for (struct property *prop = sym->prop; prop; prop = prop->next) {
1264 		    if (prop->type != P_PROMPT && prop->type != P_MENU)
1265 			    continue;
1266 		    m = prop->menu;
1267 		    break;
1268 	}
1269 
1270 	if (!m) {
1271 		/* Symbol is not visible as a menu */
1272 		symbolInfo();
1273 		emit showDebugChanged(true);
1274 	} else {
1275 		emit menuSelected(m);
1276 	}
1277 
1278 	free(result);
1279 	delete data;
1280 }
1281 
1282 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1283 {
1284 	contextMenu->popup(event->globalPos());
1285 	event->accept();
1286 }
1287 
1288 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1289 	: Parent(parent), result(NULL)
1290 {
1291 	setObjectName("search");
1292 	setWindowTitle("Search Config");
1293 
1294 	QVBoxLayout* layout1 = new QVBoxLayout(this);
1295 	layout1->setContentsMargins(11, 11, 11, 11);
1296 	layout1->setSpacing(6);
1297 
1298 	QHBoxLayout* layout2 = new QHBoxLayout();
1299 	layout2->setContentsMargins(0, 0, 0, 0);
1300 	layout2->setSpacing(6);
1301 	layout2->addWidget(new QLabel("Find:", this));
1302 	editField = new QLineEdit(this);
1303 	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1304 	layout2->addWidget(editField);
1305 	searchButton = new QPushButton("Search", this);
1306 	searchButton->setAutoDefault(false);
1307 	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1308 	layout2->addWidget(searchButton);
1309 	layout1->addLayout(layout2);
1310 
1311 	split = new QSplitter(this);
1312 	split->setOrientation(Qt::Vertical);
1313 	list = new ConfigView(split, "search");
1314 	list->list->mode = listMode;
1315 	info = new ConfigInfoView(split, "search");
1316 	connect(list->list, SIGNAL(menuChanged(struct menu *)),
1317 		info, SLOT(setInfo(struct menu *)));
1318 	connect(list->list, SIGNAL(menuChanged(struct menu *)),
1319 		parent, SLOT(setMenuLink(struct menu *)));
1320 
1321 	layout1->addWidget(split);
1322 
1323 	QVariant x, y;
1324 	int width, height;
1325 	bool ok;
1326 
1327 	configSettings->beginGroup("search");
1328 	width = configSettings->value("/window width", parent->width() / 2).toInt();
1329 	height = configSettings->value("/window height", parent->height() / 2).toInt();
1330 	resize(width, height);
1331 	x = configSettings->value("/window x");
1332 	y = configSettings->value("/window y");
1333 	if (x.isValid() && y.isValid())
1334 		move(x.toInt(), y.toInt());
1335 	QList<int> sizes = configSettings->readSizes("/split", &ok);
1336 	if (ok)
1337 		split->setSizes(sizes);
1338 	configSettings->endGroup();
1339 	connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1340 }
1341 
1342 void ConfigSearchWindow::saveSettings(void)
1343 {
1344 	if (!objectName().isEmpty()) {
1345 		configSettings->beginGroup(objectName());
1346 		configSettings->setValue("/window x", pos().x());
1347 		configSettings->setValue("/window y", pos().y());
1348 		configSettings->setValue("/window width", size().width());
1349 		configSettings->setValue("/window height", size().height());
1350 		configSettings->writeSizes("/split", split->sizes());
1351 		configSettings->endGroup();
1352 	}
1353 }
1354 
1355 void ConfigSearchWindow::search(void)
1356 {
1357 	struct symbol **p;
1358 	struct property *prop;
1359 	ConfigItem *lastItem = NULL;
1360 
1361 	free(result);
1362 	list->list->clear();
1363 	info->clear();
1364 
1365 	result = sym_re_search(editField->text().toLatin1());
1366 	if (!result)
1367 		return;
1368 	for (p = result; *p; p++) {
1369 		for_all_prompts((*p), prop)
1370 			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1371 						  menu_is_visible(prop->menu));
1372 	}
1373 }
1374 
1375 /*
1376  * Construct the complete config widget
1377  */
1378 ConfigMainWindow::ConfigMainWindow(void)
1379 	: searchWindow(0)
1380 {
1381 	bool ok = true;
1382 	QVariant x, y;
1383 	int width, height;
1384 	char title[256];
1385 
1386 	QDesktopWidget *d = configApp->desktop();
1387 	snprintf(title, sizeof(title), "%s%s",
1388 		rootmenu.prompt->text,
1389 		""
1390 		);
1391 	setWindowTitle(title);
1392 
1393 	width = configSettings->value("/window width", d->width() - 64).toInt();
1394 	height = configSettings->value("/window height", d->height() - 64).toInt();
1395 	resize(width, height);
1396 	x = configSettings->value("/window x");
1397 	y = configSettings->value("/window y");
1398 	if ((x.isValid())&&(y.isValid()))
1399 		move(x.toInt(), y.toInt());
1400 
1401 	// set up icons
1402 	ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
1403 	ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
1404 	ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
1405 	ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
1406 	ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
1407 	ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
1408 	ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
1409 
1410 	QWidget *widget = new QWidget(this);
1411 	QVBoxLayout *layout = new QVBoxLayout(widget);
1412 	setCentralWidget(widget);
1413 
1414 	split1 = new QSplitter(widget);
1415 	split1->setOrientation(Qt::Horizontal);
1416 	split1->setChildrenCollapsible(false);
1417 
1418 	menuView = new ConfigView(widget, "menu");
1419 	menuList = menuView->list;
1420 
1421 	split2 = new QSplitter(widget);
1422 	split2->setChildrenCollapsible(false);
1423 	split2->setOrientation(Qt::Vertical);
1424 
1425 	// create config tree
1426 	configView = new ConfigView(widget, "config");
1427 	configList = configView->list;
1428 
1429 	helpText = new ConfigInfoView(widget, "help");
1430 
1431 	layout->addWidget(split2);
1432 	split2->addWidget(split1);
1433 	split1->addWidget(configView);
1434 	split1->addWidget(menuView);
1435 	split2->addWidget(helpText);
1436 
1437 	setTabOrder(configList, helpText);
1438 	configList->setFocus();
1439 
1440 	backAction = new QAction(QPixmap(xpm_back), "Back", this);
1441 	connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1442 
1443 	QAction *quitAction = new QAction("&Quit", this);
1444 	quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1445 	connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1446 
1447 	QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1448 	loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1449 	connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1450 
1451 	saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1452 	saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1453 	connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1454 
1455 	conf_set_changed_callback(conf_changed);
1456 
1457 	// Set saveAction's initial state
1458 	conf_changed();
1459 	configname = xstrdup(conf_get_configname());
1460 
1461 	QAction *saveAsAction = new QAction("Save &As...", this);
1462 	  connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1463 	QAction *searchAction = new QAction("&Find", this);
1464 	searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1465 	  connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1466 	singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1467 	singleViewAction->setCheckable(true);
1468 	  connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1469 	splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1470 	splitViewAction->setCheckable(true);
1471 	  connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1472 	fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1473 	fullViewAction->setCheckable(true);
1474 	  connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1475 
1476 	QAction *showNameAction = new QAction("Show Name", this);
1477 	  showNameAction->setCheckable(true);
1478 	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1479 	  showNameAction->setChecked(configView->showName());
1480 	QAction *showRangeAction = new QAction("Show Range", this);
1481 	  showRangeAction->setCheckable(true);
1482 	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1483 	QAction *showDataAction = new QAction("Show Data", this);
1484 	  showDataAction->setCheckable(true);
1485 	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1486 
1487 	QActionGroup *optGroup = new QActionGroup(this);
1488 	optGroup->setExclusive(true);
1489 	connect(optGroup, SIGNAL(triggered(QAction*)), configList,
1490 		SLOT(setOptionMode(QAction *)));
1491 	connect(optGroup, SIGNAL(triggered(QAction *)), menuList,
1492 		SLOT(setOptionMode(QAction *)));
1493 
1494 	ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
1495 	ConfigList::showNormalAction->setCheckable(true);
1496 	ConfigList::showAllAction = new QAction("Show All Options", optGroup);
1497 	ConfigList::showAllAction->setCheckable(true);
1498 	ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
1499 	ConfigList::showPromptAction->setCheckable(true);
1500 
1501 	QAction *showDebugAction = new QAction("Show Debug Info", this);
1502 	  showDebugAction->setCheckable(true);
1503 	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1504 	  showDebugAction->setChecked(helpText->showDebug());
1505 
1506 	QAction *showIntroAction = new QAction("Introduction", this);
1507 	  connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1508 	QAction *showAboutAction = new QAction("About", this);
1509 	  connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1510 
1511 	// init tool bar
1512 	QToolBar *toolBar = addToolBar("Tools");
1513 	toolBar->addAction(backAction);
1514 	toolBar->addSeparator();
1515 	toolBar->addAction(loadAction);
1516 	toolBar->addAction(saveAction);
1517 	toolBar->addSeparator();
1518 	toolBar->addAction(singleViewAction);
1519 	toolBar->addAction(splitViewAction);
1520 	toolBar->addAction(fullViewAction);
1521 
1522 	// create file menu
1523 	QMenu *menu = menuBar()->addMenu("&File");
1524 	menu->addAction(loadAction);
1525 	menu->addAction(saveAction);
1526 	menu->addAction(saveAsAction);
1527 	menu->addSeparator();
1528 	menu->addAction(quitAction);
1529 
1530 	// create edit menu
1531 	menu = menuBar()->addMenu("&Edit");
1532 	menu->addAction(searchAction);
1533 
1534 	// create options menu
1535 	menu = menuBar()->addMenu("&Option");
1536 	menu->addAction(showNameAction);
1537 	menu->addAction(showRangeAction);
1538 	menu->addAction(showDataAction);
1539 	menu->addSeparator();
1540 	menu->addActions(optGroup->actions());
1541 	menu->addSeparator();
1542 	menu->addAction(showDebugAction);
1543 
1544 	// create help menu
1545 	menu = menuBar()->addMenu("&Help");
1546 	menu->addAction(showIntroAction);
1547 	menu->addAction(showAboutAction);
1548 
1549 	connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1550 		 helpText, SLOT (clicked (const QUrl &)) );
1551 
1552 	connect(configList, SIGNAL(menuChanged(struct menu *)),
1553 		helpText, SLOT(setInfo(struct menu *)));
1554 	connect(configList, SIGNAL(menuSelected(struct menu *)),
1555 		SLOT(changeMenu(struct menu *)));
1556 	connect(configList, SIGNAL(itemSelected(struct menu *)),
1557 		SLOT(changeItens(struct menu *)));
1558 	connect(configList, SIGNAL(parentSelected()),
1559 		SLOT(goBack()));
1560 	connect(menuList, SIGNAL(menuChanged(struct menu *)),
1561 		helpText, SLOT(setInfo(struct menu *)));
1562 	connect(menuList, SIGNAL(menuSelected(struct menu *)),
1563 		SLOT(changeMenu(struct menu *)));
1564 
1565 	connect(configList, SIGNAL(gotFocus(struct menu *)),
1566 		helpText, SLOT(setInfo(struct menu *)));
1567 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1568 		helpText, SLOT(setInfo(struct menu *)));
1569 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1570 		SLOT(listFocusChanged(void)));
1571 	connect(helpText, SIGNAL(menuSelected(struct menu *)),
1572 		SLOT(setMenuLink(struct menu *)));
1573 
1574 	QString listMode = configSettings->value("/listMode", "symbol").toString();
1575 	if (listMode == "single")
1576 		showSingleView();
1577 	else if (listMode == "full")
1578 		showFullView();
1579 	else /*if (listMode == "split")*/
1580 		showSplitView();
1581 
1582 	// UI setup done, restore splitter positions
1583 	QList<int> sizes = configSettings->readSizes("/split1", &ok);
1584 	if (ok)
1585 		split1->setSizes(sizes);
1586 
1587 	sizes = configSettings->readSizes("/split2", &ok);
1588 	if (ok)
1589 		split2->setSizes(sizes);
1590 }
1591 
1592 void ConfigMainWindow::loadConfig(void)
1593 {
1594 	QString str;
1595 	QByteArray ba;
1596 	const char *name;
1597 
1598 	str = QFileDialog::getOpenFileName(this, "", configname);
1599 	if (str.isNull())
1600 		return;
1601 
1602 	ba = str.toLocal8Bit();
1603 	name = ba.data();
1604 
1605 	if (conf_read(name))
1606 		QMessageBox::information(this, "qconf", "Unable to load configuration!");
1607 
1608 	free(configname);
1609 	configname = xstrdup(name);
1610 
1611 	ConfigView::updateListAll();
1612 }
1613 
1614 bool ConfigMainWindow::saveConfig(void)
1615 {
1616 	if (conf_write(configname)) {
1617 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1618 		return false;
1619 	}
1620 	conf_write_autoconf(0);
1621 
1622 	return true;
1623 }
1624 
1625 void ConfigMainWindow::saveConfigAs(void)
1626 {
1627 	QString str;
1628 	QByteArray ba;
1629 	const char *name;
1630 
1631 	str = QFileDialog::getSaveFileName(this, "", configname);
1632 	if (str.isNull())
1633 		return;
1634 
1635 	ba = str.toLocal8Bit();
1636 	name = ba.data();
1637 
1638 	if (conf_write(name)) {
1639 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1640 	}
1641 	conf_write_autoconf(0);
1642 
1643 	free(configname);
1644 	configname = xstrdup(name);
1645 }
1646 
1647 void ConfigMainWindow::searchConfig(void)
1648 {
1649 	if (!searchWindow)
1650 		searchWindow = new ConfigSearchWindow(this);
1651 	searchWindow->show();
1652 }
1653 
1654 void ConfigMainWindow::changeItens(struct menu *menu)
1655 {
1656 	configList->setRootMenu(menu);
1657 }
1658 
1659 void ConfigMainWindow::changeMenu(struct menu *menu)
1660 {
1661 	menuList->setRootMenu(menu);
1662 }
1663 
1664 void ConfigMainWindow::setMenuLink(struct menu *menu)
1665 {
1666 	struct menu *parent;
1667 	ConfigList* list = NULL;
1668 	ConfigItem* item;
1669 
1670 	if (configList->menuSkip(menu))
1671 		return;
1672 
1673 	switch (configList->mode) {
1674 	case singleMode:
1675 		list = configList;
1676 		parent = menu_get_parent_menu(menu);
1677 		if (!parent)
1678 			return;
1679 		list->setRootMenu(parent);
1680 		break;
1681 	case menuMode:
1682 		if (menu->flags & MENU_ROOT) {
1683 			menuList->setRootMenu(menu);
1684 			configList->clearSelection();
1685 			list = configList;
1686 		} else {
1687 			parent = menu_get_parent_menu(menu->parent);
1688 			if (!parent)
1689 				return;
1690 
1691 			/* Select the config view */
1692 			item = configList->findConfigItem(parent);
1693 			if (item) {
1694 				configList->setSelected(item, true);
1695 				configList->scrollToItem(item);
1696 			}
1697 
1698 			menuList->setRootMenu(parent);
1699 			menuList->clearSelection();
1700 			list = menuList;
1701 		}
1702 		break;
1703 	case fullMode:
1704 		list = configList;
1705 		break;
1706 	default:
1707 		break;
1708 	}
1709 
1710 	if (list) {
1711 		item = list->findConfigItem(menu);
1712 		if (item) {
1713 			list->setSelected(item, true);
1714 			list->scrollToItem(item);
1715 			list->setFocus();
1716 			helpText->setInfo(menu);
1717 		}
1718 	}
1719 }
1720 
1721 void ConfigMainWindow::listFocusChanged(void)
1722 {
1723 	if (menuList->mode == menuMode)
1724 		configList->clearSelection();
1725 }
1726 
1727 void ConfigMainWindow::goBack(void)
1728 {
1729 	if (configList->rootEntry == &rootmenu)
1730 		return;
1731 
1732 	configList->setParentMenu();
1733 }
1734 
1735 void ConfigMainWindow::showSingleView(void)
1736 {
1737 	singleViewAction->setEnabled(false);
1738 	singleViewAction->setChecked(true);
1739 	splitViewAction->setEnabled(true);
1740 	splitViewAction->setChecked(false);
1741 	fullViewAction->setEnabled(true);
1742 	fullViewAction->setChecked(false);
1743 
1744 	backAction->setEnabled(true);
1745 
1746 	menuView->hide();
1747 	menuList->setRootMenu(0);
1748 	configList->mode = singleMode;
1749 	if (configList->rootEntry == &rootmenu)
1750 		configList->updateListAll();
1751 	else
1752 		configList->setRootMenu(&rootmenu);
1753 	configList->setFocus();
1754 }
1755 
1756 void ConfigMainWindow::showSplitView(void)
1757 {
1758 	singleViewAction->setEnabled(true);
1759 	singleViewAction->setChecked(false);
1760 	splitViewAction->setEnabled(false);
1761 	splitViewAction->setChecked(true);
1762 	fullViewAction->setEnabled(true);
1763 	fullViewAction->setChecked(false);
1764 
1765 	backAction->setEnabled(false);
1766 
1767 	configList->mode = menuMode;
1768 	if (configList->rootEntry == &rootmenu)
1769 		configList->updateListAll();
1770 	else
1771 		configList->setRootMenu(&rootmenu);
1772 	configList->setAllOpen(true);
1773 	configApp->processEvents();
1774 	menuList->mode = symbolMode;
1775 	menuList->setRootMenu(&rootmenu);
1776 	menuList->setAllOpen(true);
1777 	menuView->show();
1778 	menuList->setFocus();
1779 }
1780 
1781 void ConfigMainWindow::showFullView(void)
1782 {
1783 	singleViewAction->setEnabled(true);
1784 	singleViewAction->setChecked(false);
1785 	splitViewAction->setEnabled(true);
1786 	splitViewAction->setChecked(false);
1787 	fullViewAction->setEnabled(false);
1788 	fullViewAction->setChecked(true);
1789 
1790 	backAction->setEnabled(false);
1791 
1792 	menuView->hide();
1793 	menuList->setRootMenu(0);
1794 	configList->mode = fullMode;
1795 	if (configList->rootEntry == &rootmenu)
1796 		configList->updateListAll();
1797 	else
1798 		configList->setRootMenu(&rootmenu);
1799 	configList->setFocus();
1800 }
1801 
1802 /*
1803  * ask for saving configuration before quitting
1804  */
1805 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1806 {
1807 	if (!conf_get_changed()) {
1808 		e->accept();
1809 		return;
1810 	}
1811 	QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1812 			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1813 	mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1814 	mb.setButtonText(QMessageBox::No, "&Discard Changes");
1815 	mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1816 	switch (mb.exec()) {
1817 	case QMessageBox::Yes:
1818 		if (saveConfig())
1819 			e->accept();
1820 		else
1821 			e->ignore();
1822 		break;
1823 	case QMessageBox::No:
1824 		e->accept();
1825 		break;
1826 	case QMessageBox::Cancel:
1827 		e->ignore();
1828 		break;
1829 	}
1830 }
1831 
1832 void ConfigMainWindow::showIntro(void)
1833 {
1834 	static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1835 		"For each option, a blank box indicates the feature is disabled, a check\n"
1836 		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
1837 		"as a module.  Clicking on the box will cycle through the three states.\n\n"
1838 		"If you do not see an option (e.g., a device driver) that you believe\n"
1839 		"should be present, try turning on Show All Options under the Options menu.\n"
1840 		"Although there is no cross reference yet to help you figure out what other\n"
1841 		"options must be enabled to support the option you are interested in, you can\n"
1842 		"still view the help of a grayed-out option.\n\n"
1843 		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1844 		"which you can then match by examining other options.\n\n";
1845 
1846 	QMessageBox::information(this, "qconf", str);
1847 }
1848 
1849 void ConfigMainWindow::showAbout(void)
1850 {
1851 	static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1852 		"Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1853 		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1854 
1855 	QMessageBox::information(this, "qconf", str);
1856 }
1857 
1858 void ConfigMainWindow::saveSettings(void)
1859 {
1860 	configSettings->setValue("/window x", pos().x());
1861 	configSettings->setValue("/window y", pos().y());
1862 	configSettings->setValue("/window width", size().width());
1863 	configSettings->setValue("/window height", size().height());
1864 
1865 	QString entry;
1866 	switch(configList->mode) {
1867 	case singleMode :
1868 		entry = "single";
1869 		break;
1870 
1871 	case symbolMode :
1872 		entry = "split";
1873 		break;
1874 
1875 	case fullMode :
1876 		entry = "full";
1877 		break;
1878 
1879 	default:
1880 		break;
1881 	}
1882 	configSettings->setValue("/listMode", entry);
1883 
1884 	configSettings->writeSizes("/split1", split1->sizes());
1885 	configSettings->writeSizes("/split2", split2->sizes());
1886 }
1887 
1888 void ConfigMainWindow::conf_changed(void)
1889 {
1890 	if (saveAction)
1891 		saveAction->setEnabled(conf_get_changed());
1892 }
1893 
1894 void fixup_rootmenu(struct menu *menu)
1895 {
1896 	struct menu *child;
1897 	static int menu_cnt = 0;
1898 
1899 	menu->flags |= MENU_ROOT;
1900 	for (child = menu->list; child; child = child->next) {
1901 		if (child->prompt && child->prompt->type == P_MENU) {
1902 			menu_cnt++;
1903 			fixup_rootmenu(child);
1904 			menu_cnt--;
1905 		} else if (!menu_cnt)
1906 			fixup_rootmenu(child);
1907 	}
1908 }
1909 
1910 static const char *progname;
1911 
1912 static void usage(void)
1913 {
1914 	printf("%s [-s] <config>\n", progname);
1915 	exit(0);
1916 }
1917 
1918 int main(int ac, char** av)
1919 {
1920 	ConfigMainWindow* v;
1921 	const char *name;
1922 
1923 	progname = av[0];
1924 	configApp = new QApplication(ac, av);
1925 	if (ac > 1 && av[1][0] == '-') {
1926 		switch (av[1][1]) {
1927 		case 's':
1928 			conf_set_message_callback(NULL);
1929 			break;
1930 		case 'h':
1931 		case '?':
1932 			usage();
1933 		}
1934 		name = av[2];
1935 	} else
1936 		name = av[1];
1937 	if (!name)
1938 		usage();
1939 
1940 	conf_parse(name);
1941 	fixup_rootmenu(&rootmenu);
1942 	conf_read(NULL);
1943 	//zconfdump(stdout);
1944 
1945 	configSettings = new ConfigSettings();
1946 	configSettings->beginGroup("/kconfig/qconf");
1947 	v = new ConfigMainWindow();
1948 
1949 	//zconfdump(stdout);
1950 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1951 	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1952 	v->show();
1953 	configApp->exec();
1954 
1955 	configSettings->endGroup();
1956 	delete configSettings;
1957 	delete v;
1958 	delete configApp;
1959 
1960 	return 0;
1961 }
1962