xref: /linux/scripts/kconfig/qconf.cc (revision 14b42963f64b98ab61fa9723c03d71aa5ef4f862)
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("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("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("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("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 {
1263 	QMenuBar* menu;
1264 	bool ok;
1265 	int x, y, width, height;
1266 
1267 	QWidget *d = configApp->desktop();
1268 
1269 	width = configSettings->readNumEntry("/window width", d->width() - 64);
1270 	height = configSettings->readNumEntry("/window height", d->height() - 64);
1271 	resize(width, height);
1272 	x = configSettings->readNumEntry("/window x", 0, &ok);
1273 	if (ok)
1274 		y = configSettings->readNumEntry("/window y", 0, &ok);
1275 	if (ok)
1276 		move(x, y);
1277 
1278 	split1 = new QSplitter(this);
1279 	split1->setOrientation(QSplitter::Horizontal);
1280 	setCentralWidget(split1);
1281 
1282 	menuView = new ConfigView(split1, "menu");
1283 	menuList = menuView->list;
1284 
1285 	split2 = new QSplitter(split1);
1286 	split2->setOrientation(QSplitter::Vertical);
1287 
1288 	// create config tree
1289 	configView = new ConfigView(split2, "config");
1290 	configList = configView->list;
1291 
1292 	helpText = new ConfigInfoView(split2, "help");
1293 	helpText->setTextFormat(Qt::RichText);
1294 
1295 	setTabOrder(configList, helpText);
1296 	configList->setFocus();
1297 
1298 	menu = menuBar();
1299 	toolBar = new QToolBar("Tools", this);
1300 
1301 	backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
1302 	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1303 	  backAction->setEnabled(FALSE);
1304 	QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
1305 	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
1306 	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
1307 	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1308 	QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
1309 	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1310 	QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
1311 	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1312 	QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
1313 	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1314 	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
1315 	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1316 	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
1317 	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1318 	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
1319 	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1320 
1321 	QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
1322 	  showNameAction->setToggleAction(TRUE);
1323 	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1324 	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1325 	  showNameAction->setOn(configView->showName());
1326 	QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
1327 	  showRangeAction->setToggleAction(TRUE);
1328 	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1329 	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1330 	  showRangeAction->setOn(configList->showRange);
1331 	QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
1332 	  showDataAction->setToggleAction(TRUE);
1333 	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1334 	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1335 	  showDataAction->setOn(configList->showData);
1336 	QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
1337 	  showAllAction->setToggleAction(TRUE);
1338 	  connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
1339 	  connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
1340 	  showAllAction->setOn(configList->showAll);
1341 	QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
1342 	  showDebugAction->setToggleAction(TRUE);
1343 	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1344 	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1345 	  showDebugAction->setOn(helpText->showDebug());
1346 
1347 	QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
1348 	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1349 	QAction *showAboutAction = new QAction(NULL, "About", 0, this);
1350 	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1351 
1352 	// init tool bar
1353 	backAction->addTo(toolBar);
1354 	toolBar->addSeparator();
1355 	loadAction->addTo(toolBar);
1356 	saveAction->addTo(toolBar);
1357 	toolBar->addSeparator();
1358 	singleViewAction->addTo(toolBar);
1359 	splitViewAction->addTo(toolBar);
1360 	fullViewAction->addTo(toolBar);
1361 
1362 	// create config menu
1363 	QPopupMenu* config = new QPopupMenu(this);
1364 	menu->insertItem("&File", config);
1365 	loadAction->addTo(config);
1366 	saveAction->addTo(config);
1367 	saveAsAction->addTo(config);
1368 	config->insertSeparator();
1369 	searchAction->addTo(config);
1370 	config->insertSeparator();
1371 	quitAction->addTo(config);
1372 
1373 	// create options menu
1374 	QPopupMenu* optionMenu = new QPopupMenu(this);
1375 	menu->insertItem("&Option", optionMenu);
1376 	showNameAction->addTo(optionMenu);
1377 	showRangeAction->addTo(optionMenu);
1378 	showDataAction->addTo(optionMenu);
1379 	optionMenu->insertSeparator();
1380 	showAllAction->addTo(optionMenu);
1381 	showDebugAction->addTo(optionMenu);
1382 
1383 	// create help menu
1384 	QPopupMenu* helpMenu = new QPopupMenu(this);
1385 	menu->insertSeparator();
1386 	menu->insertItem("&Help", helpMenu);
1387 	showIntroAction->addTo(helpMenu);
1388 	showAboutAction->addTo(helpMenu);
1389 
1390 	connect(configList, SIGNAL(menuChanged(struct menu *)),
1391 		helpText, SLOT(setInfo(struct menu *)));
1392 	connect(configList, SIGNAL(menuSelected(struct menu *)),
1393 		SLOT(changeMenu(struct menu *)));
1394 	connect(configList, SIGNAL(parentSelected()),
1395 		SLOT(goBack()));
1396 	connect(menuList, SIGNAL(menuChanged(struct menu *)),
1397 		helpText, SLOT(setInfo(struct menu *)));
1398 	connect(menuList, SIGNAL(menuSelected(struct menu *)),
1399 		SLOT(changeMenu(struct menu *)));
1400 
1401 	connect(configList, SIGNAL(gotFocus(struct menu *)),
1402 		helpText, SLOT(setInfo(struct menu *)));
1403 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1404 		helpText, SLOT(setInfo(struct menu *)));
1405 	connect(menuList, SIGNAL(gotFocus(struct menu *)),
1406 		SLOT(listFocusChanged(void)));
1407 	connect(helpText, SIGNAL(menuSelected(struct menu *)),
1408 		SLOT(setMenuLink(struct menu *)));
1409 
1410 	QString listMode = configSettings->readEntry("/listMode", "symbol");
1411 	if (listMode == "single")
1412 		showSingleView();
1413 	else if (listMode == "full")
1414 		showFullView();
1415 	else /*if (listMode == "split")*/
1416 		showSplitView();
1417 
1418 	// UI setup done, restore splitter positions
1419 	QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1420 	if (ok)
1421 		split1->setSizes(sizes);
1422 
1423 	sizes = configSettings->readSizes("/split2", &ok);
1424 	if (ok)
1425 		split2->setSizes(sizes);
1426 }
1427 
1428 void ConfigMainWindow::loadConfig(void)
1429 {
1430 	QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1431 	if (s.isNull())
1432 		return;
1433 	if (conf_read(QFile::encodeName(s)))
1434 		QMessageBox::information(this, "qconf", "Unable to load configuration!");
1435 	ConfigView::updateListAll();
1436 }
1437 
1438 void ConfigMainWindow::saveConfig(void)
1439 {
1440 	if (conf_write(NULL))
1441 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1442 }
1443 
1444 void ConfigMainWindow::saveConfigAs(void)
1445 {
1446 	QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1447 	if (s.isNull())
1448 		return;
1449 	if (conf_write(QFile::encodeName(s)))
1450 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1451 }
1452 
1453 void ConfigMainWindow::searchConfig(void)
1454 {
1455 	if (!searchWindow)
1456 		searchWindow = new ConfigSearchWindow(this, "search");
1457 	searchWindow->show();
1458 }
1459 
1460 void ConfigMainWindow::changeMenu(struct menu *menu)
1461 {
1462 	configList->setRootMenu(menu);
1463 	backAction->setEnabled(TRUE);
1464 }
1465 
1466 void ConfigMainWindow::setMenuLink(struct menu *menu)
1467 {
1468 	struct menu *parent;
1469 	ConfigList* list = NULL;
1470 	ConfigItem* item;
1471 
1472 	if (!menu_is_visible(menu) && !configView->showAll())
1473 		return;
1474 
1475 	switch (configList->mode) {
1476 	case singleMode:
1477 		list = configList;
1478 		parent = menu_get_parent_menu(menu);
1479 		if (!parent)
1480 			return;
1481 		list->setRootMenu(parent);
1482 		break;
1483 	case symbolMode:
1484 		if (menu->flags & MENU_ROOT) {
1485 			configList->setRootMenu(menu);
1486 			configList->clearSelection();
1487 			list = menuList;
1488 		} else {
1489 			list = configList;
1490 			parent = menu_get_parent_menu(menu->parent);
1491 			if (!parent)
1492 				return;
1493 			item = menuList->findConfigItem(parent);
1494 			if (item) {
1495 				menuList->setSelected(item, TRUE);
1496 				menuList->ensureItemVisible(item);
1497 			}
1498 			list->setRootMenu(parent);
1499 		}
1500 		break;
1501 	case fullMode:
1502 		list = configList;
1503 		break;
1504 	}
1505 
1506 	if (list) {
1507 		item = list->findConfigItem(menu);
1508 		if (item) {
1509 			list->setSelected(item, TRUE);
1510 			list->ensureItemVisible(item);
1511 			list->setFocus();
1512 		}
1513 	}
1514 }
1515 
1516 void ConfigMainWindow::listFocusChanged(void)
1517 {
1518 	if (menuList->mode == menuMode)
1519 		configList->clearSelection();
1520 }
1521 
1522 void ConfigMainWindow::goBack(void)
1523 {
1524 	ConfigItem* item;
1525 
1526 	configList->setParentMenu();
1527 	if (configList->rootEntry == &rootmenu)
1528 		backAction->setEnabled(FALSE);
1529 	item = (ConfigItem*)menuList->selectedItem();
1530 	while (item) {
1531 		if (item->menu == configList->rootEntry) {
1532 			menuList->setSelected(item, TRUE);
1533 			break;
1534 		}
1535 		item = (ConfigItem*)item->parent();
1536 	}
1537 }
1538 
1539 void ConfigMainWindow::showSingleView(void)
1540 {
1541 	menuView->hide();
1542 	menuList->setRootMenu(0);
1543 	configList->mode = singleMode;
1544 	if (configList->rootEntry == &rootmenu)
1545 		configList->updateListAll();
1546 	else
1547 		configList->setRootMenu(&rootmenu);
1548 	configList->setAllOpen(TRUE);
1549 	configList->setFocus();
1550 }
1551 
1552 void ConfigMainWindow::showSplitView(void)
1553 {
1554 	configList->mode = symbolMode;
1555 	if (configList->rootEntry == &rootmenu)
1556 		configList->updateListAll();
1557 	else
1558 		configList->setRootMenu(&rootmenu);
1559 	configList->setAllOpen(TRUE);
1560 	configApp->processEvents();
1561 	menuList->mode = menuMode;
1562 	menuList->setRootMenu(&rootmenu);
1563 	menuList->setAllOpen(TRUE);
1564 	menuView->show();
1565 	menuList->setFocus();
1566 }
1567 
1568 void ConfigMainWindow::showFullView(void)
1569 {
1570 	menuView->hide();
1571 	menuList->setRootMenu(0);
1572 	configList->mode = fullMode;
1573 	if (configList->rootEntry == &rootmenu)
1574 		configList->updateListAll();
1575 	else
1576 		configList->setRootMenu(&rootmenu);
1577 	configList->setAllOpen(FALSE);
1578 	configList->setFocus();
1579 }
1580 
1581 /*
1582  * ask for saving configuration before quitting
1583  * TODO ask only when something changed
1584  */
1585 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1586 {
1587 	if (!sym_change_count) {
1588 		e->accept();
1589 		return;
1590 	}
1591 	QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1592 			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1593 	mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1594 	mb.setButtonText(QMessageBox::No, "&Discard Changes");
1595 	mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1596 	switch (mb.exec()) {
1597 	case QMessageBox::Yes:
1598 		conf_write(NULL);
1599 	case QMessageBox::No:
1600 		e->accept();
1601 		break;
1602 	case QMessageBox::Cancel:
1603 		e->ignore();
1604 		break;
1605 	}
1606 }
1607 
1608 void ConfigMainWindow::showIntro(void)
1609 {
1610 	static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1611 		"For each option, a blank box indicates the feature is disabled, a check\n"
1612 		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
1613 		"as a module.  Clicking on the box will cycle through the three states.\n\n"
1614 		"If you do not see an option (e.g., a device driver) that you believe\n"
1615 		"should be present, try turning on Show All Options under the Options menu.\n"
1616 		"Although there is no cross reference yet to help you figure out what other\n"
1617 		"options must be enabled to support the option you are interested in, you can\n"
1618 		"still view the help of a grayed-out option.\n\n"
1619 		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1620 		"which you can then match by examining other options.\n\n";
1621 
1622 	QMessageBox::information(this, "qconf", str);
1623 }
1624 
1625 void ConfigMainWindow::showAbout(void)
1626 {
1627 	static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1628 		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1629 
1630 	QMessageBox::information(this, "qconf", str);
1631 }
1632 
1633 void ConfigMainWindow::saveSettings(void)
1634 {
1635 	configSettings->writeEntry("/window x", pos().x());
1636 	configSettings->writeEntry("/window y", pos().y());
1637 	configSettings->writeEntry("/window width", size().width());
1638 	configSettings->writeEntry("/window height", size().height());
1639 
1640 	QString entry;
1641 	switch(configList->mode) {
1642 	case singleMode :
1643 		entry = "single";
1644 		break;
1645 
1646 	case symbolMode :
1647 		entry = "split";
1648 		break;
1649 
1650 	case fullMode :
1651 		entry = "full";
1652 		break;
1653 	}
1654 	configSettings->writeEntry("/listMode", entry);
1655 
1656 	configSettings->writeSizes("/split1", split1->sizes());
1657 	configSettings->writeSizes("/split2", split2->sizes());
1658 }
1659 
1660 void fixup_rootmenu(struct menu *menu)
1661 {
1662 	struct menu *child;
1663 	static int menu_cnt = 0;
1664 
1665 	menu->flags |= MENU_ROOT;
1666 	for (child = menu->list; child; child = child->next) {
1667 		if (child->prompt && child->prompt->type == P_MENU) {
1668 			menu_cnt++;
1669 			fixup_rootmenu(child);
1670 			menu_cnt--;
1671 		} else if (!menu_cnt)
1672 			fixup_rootmenu(child);
1673 	}
1674 }
1675 
1676 static const char *progname;
1677 
1678 static void usage(void)
1679 {
1680 	printf("%s <config>\n", progname);
1681 	exit(0);
1682 }
1683 
1684 int main(int ac, char** av)
1685 {
1686 	ConfigMainWindow* v;
1687 	const char *name;
1688 
1689 	bindtextdomain(PACKAGE, LOCALEDIR);
1690 	textdomain(PACKAGE);
1691 
1692 #ifndef LKC_DIRECT_LINK
1693 	kconfig_load();
1694 #endif
1695 
1696 	progname = av[0];
1697 	configApp = new QApplication(ac, av);
1698 	if (ac > 1 && av[1][0] == '-') {
1699 		switch (av[1][1]) {
1700 		case 'h':
1701 		case '?':
1702 			usage();
1703 		}
1704 		name = av[2];
1705 	} else
1706 		name = av[1];
1707 	if (!name)
1708 		usage();
1709 
1710 	conf_parse(name);
1711 	fixup_rootmenu(&rootmenu);
1712 	conf_read(NULL);
1713 	//zconfdump(stdout);
1714 
1715 	configSettings = new ConfigSettings();
1716 	configSettings->beginGroup("/kconfig/qconf");
1717 	v = new ConfigMainWindow();
1718 
1719 	//zconfdump(stdout);
1720 	configApp->setMainWidget(v);
1721 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1722 	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1723 	v->show();
1724 	configApp->exec();
1725 
1726 	configSettings->endGroup();
1727 	delete configSettings;
1728 
1729 	return 0;
1730 }
1731