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