xref: /linux/scripts/kconfig/qconf.cc (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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 = _(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 = menu_get_help(menu);
1045 		/* Gettextize if the help text not empty */
1046 		if (help.isEmpty())
1047 			help = print_filter(menu_get_help(menu));
1048 		else
1049 			help = print_filter(_(menu_get_help(menu)));
1050 	} else if (menu->prompt) {
1051 		head += "<big><b>";
1052 		head += print_filter(_(menu->prompt->text));
1053 		head += "</b></big><br><br>";
1054 		if (showDebug()) {
1055 			if (menu->prompt->visible.expr) {
1056 				debug += "&nbsp;&nbsp;dep: ";
1057 				expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1058 				debug += "<br><br>";
1059 			}
1060 		}
1061 	}
1062 	if (showDebug())
1063 		debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
1064 
1065 	setText(head + debug + help);
1066 }
1067 
1068 QString ConfigInfoView::debug_info(struct symbol *sym)
1069 {
1070 	QString debug;
1071 
1072 	debug += "type: ";
1073 	debug += print_filter(sym_type_name(sym->type));
1074 	if (sym_is_choice(sym))
1075 		debug += " (choice)";
1076 	debug += "<br>";
1077 	if (sym->rev_dep.expr) {
1078 		debug += "reverse dep: ";
1079 		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1080 		debug += "<br>";
1081 	}
1082 	for (struct property *prop = sym->prop; prop; prop = prop->next) {
1083 		switch (prop->type) {
1084 		case P_PROMPT:
1085 		case P_MENU:
1086 			debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
1087 			debug += print_filter(_(prop->text));
1088 			debug += "</a><br>";
1089 			break;
1090 		case P_DEFAULT:
1091 		case P_SELECT:
1092 		case P_RANGE:
1093 		case P_ENV:
1094 			debug += prop_get_type_name(prop->type);
1095 			debug += ": ";
1096 			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1097 			debug += "<br>";
1098 			break;
1099 		case P_CHOICE:
1100 			if (sym_is_choice(sym)) {
1101 				debug += "choice: ";
1102 				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1103 				debug += "<br>";
1104 			}
1105 			break;
1106 		default:
1107 			debug += "unknown property: ";
1108 			debug += prop_get_type_name(prop->type);
1109 			debug += "<br>";
1110 		}
1111 		if (prop->visible.expr) {
1112 			debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1113 			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1114 			debug += "<br>";
1115 		}
1116 	}
1117 	debug += "<br>";
1118 
1119 	return debug;
1120 }
1121 
1122 QString ConfigInfoView::print_filter(const QString &str)
1123 {
1124 	QRegExp re("[<>&\"\\n]");
1125 	QString res = str;
1126 	for (int i = 0; (i = res.find(re, i)) >= 0;) {
1127 		switch (res[i].latin1()) {
1128 		case '<':
1129 			res.replace(i, 1, "&lt;");
1130 			i += 4;
1131 			break;
1132 		case '>':
1133 			res.replace(i, 1, "&gt;");
1134 			i += 4;
1135 			break;
1136 		case '&':
1137 			res.replace(i, 1, "&amp;");
1138 			i += 5;
1139 			break;
1140 		case '"':
1141 			res.replace(i, 1, "&quot;");
1142 			i += 6;
1143 			break;
1144 		case '\n':
1145 			res.replace(i, 1, "<br>");
1146 			i += 4;
1147 			break;
1148 		}
1149 	}
1150 	return res;
1151 }
1152 
1153 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1154 {
1155 	QString* text = reinterpret_cast<QString*>(data);
1156 	QString str2 = print_filter(str);
1157 
1158 	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1159 		*text += QString().sprintf("<a href=\"s%p\">", sym);
1160 		*text += str2;
1161 		*text += "</a>";
1162 	} else
1163 		*text += str2;
1164 }
1165 
1166 QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
1167 {
1168 	QPopupMenu* popup = Parent::createPopupMenu(pos);
1169 	QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup);
1170 	  action->setToggleAction(TRUE);
1171 	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1172 	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1173 	  action->setOn(showDebug());
1174 	popup->insertSeparator();
1175 	action->addTo(popup);
1176 	return popup;
1177 }
1178 
1179 void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
1180 {
1181 	Parent::contentsContextMenuEvent(e);
1182 }
1183 
1184 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1185 	: Parent(parent, name), result(NULL)
1186 {
1187 	setCaption("Search Config");
1188 
1189 	QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
1190 	QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
1191 	layout2->addWidget(new QLabel(_("Find:"), this));
1192 	editField = new QLineEdit(this);
1193 	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1194 	layout2->addWidget(editField);
1195 	searchButton = new QPushButton(_("Search"), this);
1196 	searchButton->setAutoDefault(FALSE);
1197 	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1198 	layout2->addWidget(searchButton);
1199 	layout1->addLayout(layout2);
1200 
1201 	split = new QSplitter(this);
1202 	split->setOrientation(QSplitter::Vertical);
1203 	list = new ConfigView(split, name);
1204 	list->list->mode = listMode;
1205 	info = new ConfigInfoView(split, name);
1206 	connect(list->list, SIGNAL(menuChanged(struct menu *)),
1207 		info, SLOT(setInfo(struct menu *)));
1208 	connect(list->list, SIGNAL(menuChanged(struct menu *)),
1209 		parent, SLOT(setMenuLink(struct menu *)));
1210 
1211 	layout1->addWidget(split);
1212 
1213 	if (name) {
1214 		int x, y, width, height;
1215 		bool ok;
1216 
1217 		configSettings->beginGroup(name);
1218 		width = configSettings->readNumEntry("/window width", parent->width() / 2);
1219 		height = configSettings->readNumEntry("/window height", parent->height() / 2);
1220 		resize(width, height);
1221 		x = configSettings->readNumEntry("/window x", 0, &ok);
1222 		if (ok)
1223 			y = configSettings->readNumEntry("/window y", 0, &ok);
1224 		if (ok)
1225 			move(x, y);
1226 		QValueList<int> sizes = configSettings->readSizes("/split", &ok);
1227 		if (ok)
1228 			split->setSizes(sizes);
1229 		configSettings->endGroup();
1230 		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1231 	}
1232 }
1233 
1234 void ConfigSearchWindow::saveSettings(void)
1235 {
1236 	if (name()) {
1237 		configSettings->beginGroup(name());
1238 		configSettings->writeEntry("/window x", pos().x());
1239 		configSettings->writeEntry("/window y", pos().y());
1240 		configSettings->writeEntry("/window width", size().width());
1241 		configSettings->writeEntry("/window height", size().height());
1242 		configSettings->writeSizes("/split", split->sizes());
1243 		configSettings->endGroup();
1244 	}
1245 }
1246 
1247 void ConfigSearchWindow::search(void)
1248 {
1249 	struct symbol **p;
1250 	struct property *prop;
1251 	ConfigItem *lastItem = NULL;
1252 
1253 	free(result);
1254 	list->list->clear();
1255 	info->clear();
1256 
1257 	result = sym_re_search(editField->text().latin1());
1258 	if (!result)
1259 		return;
1260 	for (p = result; *p; p++) {
1261 		for_all_prompts((*p), prop)
1262 			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1263 						  menu_is_visible(prop->menu));
1264 	}
1265 }
1266 
1267 /*
1268  * Construct the complete config widget
1269  */
1270 ConfigMainWindow::ConfigMainWindow(void)
1271 	: searchWindow(0)
1272 {
1273 	QMenuBar* menu;
1274 	bool ok;
1275 	int x, y, width, height;
1276 	char title[256];
1277 
1278 	QWidget *d = configApp->desktop();
1279 	snprintf(title, sizeof(title), _("Linux Kernel v%s Configuration"),
1280 		getenv("KERNELVERSION"));
1281 	setCaption(title);
1282 
1283 	width = configSettings->readNumEntry("/window width", d->width() - 64);
1284 	height = configSettings->readNumEntry("/window height", d->height() - 64);
1285 	resize(width, height);
1286 	x = configSettings->readNumEntry("/window x", 0, &ok);
1287 	if (ok)
1288 		y = configSettings->readNumEntry("/window y", 0, &ok);
1289 	if (ok)
1290 		move(x, y);
1291 
1292 	split1 = new QSplitter(this);
1293 	split1->setOrientation(QSplitter::Horizontal);
1294 	setCentralWidget(split1);
1295 
1296 	menuView = new ConfigView(split1, "menu");
1297 	menuList = menuView->list;
1298 
1299 	split2 = new QSplitter(split1);
1300 	split2->setOrientation(QSplitter::Vertical);
1301 
1302 	// create config tree
1303 	configView = new ConfigView(split2, "config");
1304 	configList = configView->list;
1305 
1306 	helpText = new ConfigInfoView(split2, "help");
1307 	helpText->setTextFormat(Qt::RichText);
1308 
1309 	setTabOrder(configList, helpText);
1310 	configList->setFocus();
1311 
1312 	menu = menuBar();
1313 	toolBar = new QToolBar("Tools", this);
1314 
1315 	backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
1316 	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1317 	  backAction->setEnabled(FALSE);
1318 	QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this);
1319 	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
1320 	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this);
1321 	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1322 	saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this);
1323 	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1324 	conf_set_changed_callback(conf_changed);
1325 	// Set saveAction's initial state
1326 	conf_changed();
1327 	QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
1328 	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1329 	QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this);
1330 	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1331 	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
1332 	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1333 	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
1334 	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1335 	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
1336 	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1337 
1338 	QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this);
1339 	  showNameAction->setToggleAction(TRUE);
1340 	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1341 	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1342 	  showNameAction->setOn(configView->showName());
1343 	QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this);
1344 	  showRangeAction->setToggleAction(TRUE);
1345 	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1346 	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1347 	  showRangeAction->setOn(configList->showRange);
1348 	QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this);
1349 	  showDataAction->setToggleAction(TRUE);
1350 	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1351 	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1352 	  showDataAction->setOn(configList->showData);
1353 	QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
1354 	  showAllAction->setToggleAction(TRUE);
1355 	  connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
1356 	  connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
1357 	  showAllAction->setOn(configList->showAll);
1358 	QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
1359 	  showDebugAction->setToggleAction(TRUE);
1360 	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1361 	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1362 	  showDebugAction->setOn(helpText->showDebug());
1363 
1364 	QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this);
1365 	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1366 	QAction *showAboutAction = new QAction(NULL, _("About"), 0, this);
1367 	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1368 
1369 	// init tool bar
1370 	backAction->addTo(toolBar);
1371 	toolBar->addSeparator();
1372 	loadAction->addTo(toolBar);
1373 	saveAction->addTo(toolBar);
1374 	toolBar->addSeparator();
1375 	singleViewAction->addTo(toolBar);
1376 	splitViewAction->addTo(toolBar);
1377 	fullViewAction->addTo(toolBar);
1378 
1379 	// create config menu
1380 	QPopupMenu* config = new QPopupMenu(this);
1381 	menu->insertItem(_("&File"), config);
1382 	loadAction->addTo(config);
1383 	saveAction->addTo(config);
1384 	saveAsAction->addTo(config);
1385 	config->insertSeparator();
1386 	quitAction->addTo(config);
1387 
1388 	// create edit menu
1389 	QPopupMenu* editMenu = new QPopupMenu(this);
1390 	menu->insertItem(_("&Edit"), editMenu);
1391 	searchAction->addTo(editMenu);
1392 
1393 	// create options menu
1394 	QPopupMenu* optionMenu = new QPopupMenu(this);
1395 	menu->insertItem(_("&Option"), optionMenu);
1396 	showNameAction->addTo(optionMenu);
1397 	showRangeAction->addTo(optionMenu);
1398 	showDataAction->addTo(optionMenu);
1399 	optionMenu->insertSeparator();
1400 	showAllAction->addTo(optionMenu);
1401 	showDebugAction->addTo(optionMenu);
1402 
1403 	// create help menu
1404 	QPopupMenu* helpMenu = new QPopupMenu(this);
1405 	menu->insertSeparator();
1406 	menu->insertItem(_("&Help"), helpMenu);
1407 	showIntroAction->addTo(helpMenu);
1408 	showAboutAction->addTo(helpMenu);
1409 
1410 	connect(configList, SIGNAL(menuChanged(struct menu *)),
1411 		helpText, SLOT(setInfo(struct menu *)));
1412 	connect(configList, SIGNAL(menuSelected(struct menu *)),
1413 		SLOT(changeMenu(struct menu *)));
1414 	connect(configList, SIGNAL(parentSelected()),
1415 		SLOT(goBack()));
1416 	connect(menuList, SIGNAL(menuChanged(struct menu *)),
1417 		helpText, SLOT(setInfo(struct menu *)));
1418 	connect(menuList, SIGNAL(menuSelected(struct menu *)),
1419 		SLOT(changeMenu(struct menu *)));
1420 
1421 	connect(configList, SIGNAL(gotFocus(struct menu *)),
1422 		helpText, SLOT(setInfo(struct menu *)));
1423 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1424 		helpText, SLOT(setInfo(struct menu *)));
1425 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1426 		SLOT(listFocusChanged(void)));
1427 	connect(helpText, SIGNAL(menuSelected(struct menu *)),
1428 		SLOT(setMenuLink(struct menu *)));
1429 
1430 	QString listMode = configSettings->readEntry("/listMode", "symbol");
1431 	if (listMode == "single")
1432 		showSingleView();
1433 	else if (listMode == "full")
1434 		showFullView();
1435 	else /*if (listMode == "split")*/
1436 		showSplitView();
1437 
1438 	// UI setup done, restore splitter positions
1439 	QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1440 	if (ok)
1441 		split1->setSizes(sizes);
1442 
1443 	sizes = configSettings->readSizes("/split2", &ok);
1444 	if (ok)
1445 		split2->setSizes(sizes);
1446 }
1447 
1448 void ConfigMainWindow::loadConfig(void)
1449 {
1450 	QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1451 	if (s.isNull())
1452 		return;
1453 	if (conf_read(QFile::encodeName(s)))
1454 		QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
1455 	ConfigView::updateListAll();
1456 }
1457 
1458 void ConfigMainWindow::saveConfig(void)
1459 {
1460 	if (conf_write(NULL))
1461 		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
1462 }
1463 
1464 void ConfigMainWindow::saveConfigAs(void)
1465 {
1466 	QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1467 	if (s.isNull())
1468 		return;
1469 	if (conf_write(QFile::encodeName(s)))
1470 		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
1471 }
1472 
1473 void ConfigMainWindow::searchConfig(void)
1474 {
1475 	if (!searchWindow)
1476 		searchWindow = new ConfigSearchWindow(this, "search");
1477 	searchWindow->show();
1478 }
1479 
1480 void ConfigMainWindow::changeMenu(struct menu *menu)
1481 {
1482 	configList->setRootMenu(menu);
1483 	if (configList->rootEntry->parent == &rootmenu)
1484 		backAction->setEnabled(FALSE);
1485 	else
1486 		backAction->setEnabled(TRUE);
1487 }
1488 
1489 void ConfigMainWindow::setMenuLink(struct menu *menu)
1490 {
1491 	struct menu *parent;
1492 	ConfigList* list = NULL;
1493 	ConfigItem* item;
1494 
1495 	if (!menu_is_visible(menu) && !configView->showAll())
1496 		return;
1497 
1498 	switch (configList->mode) {
1499 	case singleMode:
1500 		list = configList;
1501 		parent = menu_get_parent_menu(menu);
1502 		if (!parent)
1503 			return;
1504 		list->setRootMenu(parent);
1505 		break;
1506 	case symbolMode:
1507 		if (menu->flags & MENU_ROOT) {
1508 			configList->setRootMenu(menu);
1509 			configList->clearSelection();
1510 			list = menuList;
1511 		} else {
1512 			list = configList;
1513 			parent = menu_get_parent_menu(menu->parent);
1514 			if (!parent)
1515 				return;
1516 			item = menuList->findConfigItem(parent);
1517 			if (item) {
1518 				menuList->setSelected(item, TRUE);
1519 				menuList->ensureItemVisible(item);
1520 			}
1521 			list->setRootMenu(parent);
1522 		}
1523 		break;
1524 	case fullMode:
1525 		list = configList;
1526 		break;
1527 	}
1528 
1529 	if (list) {
1530 		item = list->findConfigItem(menu);
1531 		if (item) {
1532 			list->setSelected(item, TRUE);
1533 			list->ensureItemVisible(item);
1534 			list->setFocus();
1535 		}
1536 	}
1537 }
1538 
1539 void ConfigMainWindow::listFocusChanged(void)
1540 {
1541 	if (menuList->mode == menuMode)
1542 		configList->clearSelection();
1543 }
1544 
1545 void ConfigMainWindow::goBack(void)
1546 {
1547 	ConfigItem* item;
1548 
1549 	configList->setParentMenu();
1550 	if (configList->rootEntry == &rootmenu)
1551 		backAction->setEnabled(FALSE);
1552 	item = (ConfigItem*)menuList->selectedItem();
1553 	while (item) {
1554 		if (item->menu == configList->rootEntry) {
1555 			menuList->setSelected(item, TRUE);
1556 			break;
1557 		}
1558 		item = (ConfigItem*)item->parent();
1559 	}
1560 }
1561 
1562 void ConfigMainWindow::showSingleView(void)
1563 {
1564 	menuView->hide();
1565 	menuList->setRootMenu(0);
1566 	configList->mode = singleMode;
1567 	if (configList->rootEntry == &rootmenu)
1568 		configList->updateListAll();
1569 	else
1570 		configList->setRootMenu(&rootmenu);
1571 	configList->setAllOpen(TRUE);
1572 	configList->setFocus();
1573 }
1574 
1575 void ConfigMainWindow::showSplitView(void)
1576 {
1577 	configList->mode = symbolMode;
1578 	if (configList->rootEntry == &rootmenu)
1579 		configList->updateListAll();
1580 	else
1581 		configList->setRootMenu(&rootmenu);
1582 	configList->setAllOpen(TRUE);
1583 	configApp->processEvents();
1584 	menuList->mode = menuMode;
1585 	menuList->setRootMenu(&rootmenu);
1586 	menuList->setAllOpen(TRUE);
1587 	menuView->show();
1588 	menuList->setFocus();
1589 }
1590 
1591 void ConfigMainWindow::showFullView(void)
1592 {
1593 	menuView->hide();
1594 	menuList->setRootMenu(0);
1595 	configList->mode = fullMode;
1596 	if (configList->rootEntry == &rootmenu)
1597 		configList->updateListAll();
1598 	else
1599 		configList->setRootMenu(&rootmenu);
1600 	configList->setAllOpen(FALSE);
1601 	configList->setFocus();
1602 }
1603 
1604 /*
1605  * ask for saving configuration before quitting
1606  * TODO ask only when something changed
1607  */
1608 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1609 {
1610 	if (!conf_get_changed()) {
1611 		e->accept();
1612 		return;
1613 	}
1614 	QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
1615 			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1616 	mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
1617 	mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
1618 	mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
1619 	switch (mb.exec()) {
1620 	case QMessageBox::Yes:
1621 		conf_write(NULL);
1622 	case QMessageBox::No:
1623 		e->accept();
1624 		break;
1625 	case QMessageBox::Cancel:
1626 		e->ignore();
1627 		break;
1628 	}
1629 }
1630 
1631 void ConfigMainWindow::showIntro(void)
1632 {
1633 	static const QString str = _("Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1634 		"For each option, a blank box indicates the feature is disabled, a check\n"
1635 		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
1636 		"as a module.  Clicking on the box will cycle through the three states.\n\n"
1637 		"If you do not see an option (e.g., a device driver) that you believe\n"
1638 		"should be present, try turning on Show All Options under the Options menu.\n"
1639 		"Although there is no cross reference yet to help you figure out what other\n"
1640 		"options must be enabled to support the option you are interested in, you can\n"
1641 		"still view the help of a grayed-out option.\n\n"
1642 		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1643 		"which you can then match by examining other options.\n\n");
1644 
1645 	QMessageBox::information(this, "qconf", str);
1646 }
1647 
1648 void ConfigMainWindow::showAbout(void)
1649 {
1650 	static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1651 		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
1652 
1653 	QMessageBox::information(this, "qconf", str);
1654 }
1655 
1656 void ConfigMainWindow::saveSettings(void)
1657 {
1658 	configSettings->writeEntry("/window x", pos().x());
1659 	configSettings->writeEntry("/window y", pos().y());
1660 	configSettings->writeEntry("/window width", size().width());
1661 	configSettings->writeEntry("/window height", size().height());
1662 
1663 	QString entry;
1664 	switch(configList->mode) {
1665 	case singleMode :
1666 		entry = "single";
1667 		break;
1668 
1669 	case symbolMode :
1670 		entry = "split";
1671 		break;
1672 
1673 	case fullMode :
1674 		entry = "full";
1675 		break;
1676 	}
1677 	configSettings->writeEntry("/listMode", entry);
1678 
1679 	configSettings->writeSizes("/split1", split1->sizes());
1680 	configSettings->writeSizes("/split2", split2->sizes());
1681 }
1682 
1683 void ConfigMainWindow::conf_changed(void)
1684 {
1685 	if (saveAction)
1686 		saveAction->setEnabled(conf_get_changed());
1687 }
1688 
1689 void fixup_rootmenu(struct menu *menu)
1690 {
1691 	struct menu *child;
1692 	static int menu_cnt = 0;
1693 
1694 	menu->flags |= MENU_ROOT;
1695 	for (child = menu->list; child; child = child->next) {
1696 		if (child->prompt && child->prompt->type == P_MENU) {
1697 			menu_cnt++;
1698 			fixup_rootmenu(child);
1699 			menu_cnt--;
1700 		} else if (!menu_cnt)
1701 			fixup_rootmenu(child);
1702 	}
1703 }
1704 
1705 static const char *progname;
1706 
1707 static void usage(void)
1708 {
1709 	printf(_("%s <config>\n"), progname);
1710 	exit(0);
1711 }
1712 
1713 int main(int ac, char** av)
1714 {
1715 	ConfigMainWindow* v;
1716 	const char *name;
1717 
1718 	bindtextdomain(PACKAGE, LOCALEDIR);
1719 	textdomain(PACKAGE);
1720 
1721 #ifndef LKC_DIRECT_LINK
1722 	kconfig_load();
1723 #endif
1724 
1725 	progname = av[0];
1726 	configApp = new QApplication(ac, av);
1727 	if (ac > 1 && av[1][0] == '-') {
1728 		switch (av[1][1]) {
1729 		case 'h':
1730 		case '?':
1731 			usage();
1732 		}
1733 		name = av[2];
1734 	} else
1735 		name = av[1];
1736 	if (!name)
1737 		usage();
1738 
1739 	conf_parse(name);
1740 	fixup_rootmenu(&rootmenu);
1741 	conf_read(NULL);
1742 	//zconfdump(stdout);
1743 
1744 	configSettings = new ConfigSettings();
1745 	configSettings->beginGroup("/kconfig/qconf");
1746 	v = new ConfigMainWindow();
1747 
1748 	//zconfdump(stdout);
1749 	configApp->setMainWidget(v);
1750 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1751 	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1752 	v->show();
1753 	configApp->exec();
1754 
1755 	configSettings->endGroup();
1756 	delete configSettings;
1757 
1758 	return 0;
1759 }
1760