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