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