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