Linux Audio

Check our new training course

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