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