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