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