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