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