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