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