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