qconf.cc 45.1 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
L
Linus Torvalds 已提交
2 3
/*
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4
 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
L
Linus Torvalds 已提交
5 6
 */

7
#include <QAction>
8 9
#include <QApplication>
#include <QCloseEvent>
10
#include <QDebug>
11
#include <QDesktopWidget>
12
#include <QFileDialog>
13 14 15
#include <QLabel>
#include <QLayout>
#include <QList>
16
#include <QMenu>
17 18 19
#include <QMenuBar>
#include <QMessageBox>
#include <QToolBar>
L
Linus Torvalds 已提交
20 21 22 23 24 25

#include <stdlib.h>

#include "lkc.h"
#include "qconf.h"

26
#include "images.h"
L
Linus Torvalds 已提交
27

28

L
Linus Torvalds 已提交
29
static QApplication *configApp;
30
static ConfigSettings *configSettings;
L
Linus Torvalds 已提交
31

32
QAction *ConfigMainWindow::saveAction;
33

34 35
static inline QString qgettext(const char* str)
{
36
	return QString::fromLocal8Bit(str);
37 38
}

39 40 41 42 43
ConfigSettings::ConfigSettings()
	: QSettings("kernel.org", "qconf")
{
}

L
Linus Torvalds 已提交
44 45 46
/**
 * Reads a list of integer values from the application settings.
 */
47
QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
L
Linus Torvalds 已提交
48
{
49
	QList<int> result;
L
Li Zefan 已提交
50

51 52 53 54 55 56 57 58 59 60 61 62
	if (contains(key))
	{
		QStringList entryList = value(key).toStringList();
		QStringList::Iterator it;

		for (it = entryList.begin(); it != entryList.end(); ++it)
			result.push_back((*it).toInt());

		*ok = true;
	}
	else
		*ok = false;
L
Linus Torvalds 已提交
63 64 65 66 67 68 69

	return result;
}

/**
 * Writes a list of integer values to the application settings.
 */
70
bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
L
Linus Torvalds 已提交
71 72
{
	QStringList stringList;
73
	QList<int>::ConstIterator it;
L
Linus Torvalds 已提交
74 75 76

	for (it = value.begin(); it != value.end(); ++it)
		stringList.push_back(QString::number(*it));
77
	setValue(key, stringList);
78

79
	return true;
L
Linus Torvalds 已提交
80 81
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95

/*
 * set the new data
 * TODO check the value
 */
void ConfigItem::okRename(int col)
{
}

/*
 * update the displayed of a menu entry
 */
void ConfigItem::updateMenu(void)
{
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
	ConfigList* list;
	struct symbol* sym;
	struct property *prop;
	QString prompt;
	int type;
	tristate expr;

	list = listView();
	if (goParent) {
		setPixmap(promptColIdx, list->menuBackPix);
		prompt = "..";
		goto set_prompt;
	}

	sym = menu->sym;
	prop = menu->prompt;
112
	prompt = qgettext(menu_get_prompt(menu));
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

	if (prop) switch (prop->type) {
	case P_MENU:
		if (list->mode == singleMode || list->mode == symbolMode) {
			/* a menuconfig entry is displayed differently
			 * depending whether it's at the view root or a child.
			 */
			if (sym && list->rootEntry == menu)
				break;
			setPixmap(promptColIdx, list->menuPix);
		} else {
			if (sym)
				break;
			setPixmap(promptColIdx, QIcon());
		}
		goto set_prompt;
	case P_COMMENT:
		setPixmap(promptColIdx, QIcon());
		goto set_prompt;
	default:
		;
	}
	if (!sym)
		goto set_prompt;

	setText(nameColIdx, QString::fromLocal8Bit(sym->name));

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		char ch;

146
		if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
147
			setPixmap(promptColIdx, QIcon());
148 149 150
			setText(noColIdx, QString());
			setText(modColIdx, QString());
			setText(yesColIdx, QString());
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
			break;
		}
		expr = sym_get_tristate_value(sym);
		switch (expr) {
		case yes:
			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
				setPixmap(promptColIdx, list->choiceYesPix);
			else
				setPixmap(promptColIdx, list->symbolYesPix);
			setText(yesColIdx, "Y");
			ch = 'Y';
			break;
		case mod:
			setPixmap(promptColIdx, list->symbolModPix);
			setText(modColIdx, "M");
			ch = 'M';
			break;
		default:
			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
				setPixmap(promptColIdx, list->choiceNoPix);
			else
				setPixmap(promptColIdx, list->symbolNoPix);
			setText(noColIdx, "N");
			ch = 'N';
			break;
		}
		if (expr != no)
			setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
		if (expr != mod)
			setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
		if (expr != yes)
			setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);

		setText(dataColIdx, QChar(ch));
		break;
	case S_INT:
	case S_HEX:
	case S_STRING:
		const char* data;

		data = sym_get_string_value(sym);

		setText(dataColIdx, data);
		if (type == S_STRING)
			prompt = QString("%1: %2").arg(prompt).arg(data);
		else
			prompt = QString("(%2) %1").arg(prompt).arg(data);
		break;
	}
	if (!sym_has_value(sym) && visible)
201
		prompt += " (NEW)";
202 203
set_prompt:
	setText(promptColIdx, prompt);
204 205 206 207
}

void ConfigItem::testUpdateMenu(bool v)
{
208 209 210 211 212 213 214 215 216 217 218 219 220 221
	ConfigItem* i;

	visible = v;
	if (!menu)
		return;

	sym_calc_value(menu->sym);
	if (menu->flags & MENU_CHANGED) {
		/* the menu entry changed, so update all list items */
		menu->flags &= ~MENU_CHANGED;
		for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
			i->updateMenu();
	} else if (listView()->updateAll)
		updateMenu();
222 223 224
}


225 226 227 228 229
/*
 * construct a menu entry
 */
void ConfigItem::init(void)
{
230 231 232 233 234 235 236 237 238 239
	if (menu) {
		ConfigList* list = listView();
		nextItem = (ConfigItem*)menu->data;
		menu->data = this;

		if (list->mode != fullMode)
			setExpanded(true);
		sym_calc_value(menu->sym);
	}
	updateMenu();
240 241 242 243 244 245 246
}

/*
 * destruct a menu entry
 */
ConfigItem::~ConfigItem(void)
{
247 248 249 250 251 252 253 254 255
	if (menu) {
		ConfigItem** ip = (ConfigItem**)&menu->data;
		for (; *ip; ip = &(*ip)->nextItem) {
			if (*ip == this) {
				*ip = nextItem;
				break;
			}
		}
	}
256 257
}

258 259 260
ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
	: Parent(parent)
{
261
	connect(this, SIGNAL(editingFinished()), SLOT(hide()));
262 263
}

264
void ConfigLineEdit::show(ConfigItem* i)
L
Linus Torvalds 已提交
265 266
{
	item = i;
267 268 269
	if (sym_get_string_value(item->menu->sym))
		setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
	else
270
		setText(QString());
L
Linus Torvalds 已提交
271 272 273 274 275 276 277
	Parent::show();
	setFocus();
}

void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
{
	switch (e->key()) {
278
	case Qt::Key_Escape:
L
Linus Torvalds 已提交
279
		break;
280 281
	case Qt::Key_Return:
	case Qt::Key_Enter:
282
		sym_set_string_value(item->menu->sym, text().toLatin1());
283
		parent()->updateList();
L
Linus Torvalds 已提交
284 285 286 287 288 289 290 291 292 293
		break;
	default:
		Parent::keyPressEvent(e);
		return;
	}
	e->accept();
	parent()->list->setFocus();
	hide();
}

294
ConfigList::ConfigList(ConfigView* p, const char *name)
295 296 297 298 299
	: Parent(p),
	  updateAll(false),
	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
300
	  showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
301 302
	  rootEntry(0), headerPopup(0)
{
303
	setObjectName(name);
304
	setSortingEnabled(false);
305 306
	setRootIsDecorated(true);

307 308 309
	setVerticalScrollMode(ScrollPerPixel);
	setHorizontalScrollMode(ScrollPerPixel);

310
	setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
311

312
	connect(this, SIGNAL(itemSelectionChanged(void)),
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
		SLOT(updateSelection(void)));

	if (name) {
		configSettings->beginGroup(name);
		showName = configSettings->value("/showName", false).toBool();
		showRange = configSettings->value("/showRange", false).toBool();
		showData = configSettings->value("/showData", false).toBool();
		optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
		configSettings->endGroup();
		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
	}

	addColumn(promptColIdx);

	reinit();
}

bool ConfigList::menuSkip(struct menu *menu)
{
	if (optMode == normalOpt && menu_is_visible(menu))
		return false;
	if (optMode == promptOpt && menu_has_prompt(menu))
		return false;
	if (optMode == allOpt)
		return false;
	return true;
339 340 341 342
}

void ConfigList::reinit(void)
{
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
	removeColumn(dataColIdx);
	removeColumn(yesColIdx);
	removeColumn(modColIdx);
	removeColumn(noColIdx);
	removeColumn(nameColIdx);

	if (showName)
		addColumn(nameColIdx);
	if (showRange) {
		addColumn(noColIdx);
		addColumn(modColIdx);
		addColumn(yesColIdx);
	}
	if (showData)
		addColumn(dataColIdx);

	updateListAll();
360 361 362 363
}

void ConfigList::saveSettings(void)
{
364 365 366 367 368 369 370 371
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/showName", showName);
		configSettings->setValue("/showRange", showRange);
		configSettings->setValue("/showData", showData);
		configSettings->setValue("/optionMode", (int)optMode);
		configSettings->endGroup();
	}
372 373 374 375
}

ConfigItem* ConfigList::findConfigItem(struct menu *menu)
{
376 377 378 379 380 381 382 383
	ConfigItem* item = (ConfigItem*)menu->data;

	for (; item; item = item->nextItem) {
		if (this == item->listView())
			break;
	}

	return item;
384 385 386 387
}

void ConfigList::updateSelection(void)
{
388 389 390
	struct menu *menu;
	enum prop_type type;

B
Boris Barbulovski 已提交
391 392 393
	if (selectedItems().count() == 0)
		return;

394 395 396 397 398 399 400 401 402 403 404
	ConfigItem* item = (ConfigItem*)selectedItems().first();
	if (!item)
		return;

	menu = item->menu;
	emit menuChanged(menu);
	if (!menu)
		return;
	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
	if (mode == menuMode && type == P_MENU)
		emit menuSelected(menu);
405 406
}

407
void ConfigList::updateList()
408
{
409
	ConfigItem* last = 0;
410
	ConfigItem *item;
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429

	if (!rootEntry) {
		if (mode != listMode)
			goto update;
		QTreeWidgetItemIterator it(this);

		while (*it) {
			item = (ConfigItem*)(*it);
			if (!item->menu)
				continue;
			item->testUpdateMenu(menu_is_visible(item->menu));

			++it;
		}
		return;
	}

	if (rootEntry != &rootmenu && (mode == singleMode ||
	    (mode == symbolMode && rootEntry->parent != &rootmenu))) {
430
		item = (ConfigItem *)topLevelItem(0);
431
		if (!item)
432
			item = new ConfigItem(this, 0, true);
433
		last = item;
434 435 436
	}
	if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
	    rootEntry->sym && rootEntry->prompt) {
437
		item = last ? last->nextSibling() : nullptr;
438 439 440 441 442 443 444
		if (!item)
			item = new ConfigItem(this, last, rootEntry, true);
		else
			item->testUpdateMenu(true);

		updateMenuList(item, rootEntry);
		update();
445
		resizeColumnToContents(0);
446 447 448
		return;
	}
update:
449
	updateMenuList(rootEntry);
450
	update();
451
	resizeColumnToContents(0);
452 453 454 455
}

void ConfigList::setValue(ConfigItem* item, tristate val)
{
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
	struct symbol* sym;
	int type;
	tristate oldval;

	sym = item->menu ? item->menu->sym : 0;
	if (!sym)
		return;

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		oldval = sym_get_tristate_value(sym);

		if (!sym_set_tristate_value(sym, val))
			return;
		if (oldval == no && item->menu->list)
			item->setExpanded(true);
474
		parent()->updateList();
475 476
		break;
	}
477 478 479 480
}

void ConfigList::changeValue(ConfigItem* item)
{
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
	struct symbol* sym;
	struct menu* menu;
	int type, oldexpr, newexpr;

	menu = item->menu;
	if (!menu)
		return;
	sym = menu->sym;
	if (!sym) {
		if (item->menu->list)
			item->setExpanded(!item->isExpanded());
		return;
	}

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		oldexpr = sym_get_tristate_value(sym);
		newexpr = sym_toggle_tristate_value(sym);
		if (item->menu->list) {
			if (oldexpr == newexpr)
				item->setExpanded(!item->isExpanded());
			else if (oldexpr == no)
				item->setExpanded(true);
		}
		if (oldexpr != newexpr)
508
			parent()->updateList();
509 510 511 512
		break;
	case S_INT:
	case S_HEX:
	case S_STRING:
513
		parent()->lineEdit->show(item);
514 515
		break;
	}
516 517 518 519
}

void ConfigList::setRootMenu(struct menu *menu)
{
520 521 522 523 524 525 526
	enum prop_type type;

	if (rootEntry == menu)
		return;
	type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
	if (type != P_MENU)
		return;
527
	updateMenuList(0);
528 529 530
	rootEntry = menu;
	updateListAll();
	if (currentItem()) {
531
		setSelected(currentItem(), hasFocus());
532 533
		scrollToItem(currentItem());
	}
534 535 536 537
}

void ConfigList::setParentMenu(void)
{
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
	ConfigItem* item;
	struct menu *oldroot;

	oldroot = rootEntry;
	if (rootEntry == &rootmenu)
		return;
	setRootMenu(menu_get_parent_menu(rootEntry->parent));

	QTreeWidgetItemIterator it(this);
	while (*it) {
		item = (ConfigItem *)(*it);
		if (item->menu == oldroot) {
			setCurrentItem(item);
			scrollToItem(item);
			break;
		}

		++it;
	}
557 558 559 560 561 562 563 564 565
}

/*
 * update all the children of a menu entry
 *   removes/adds the entries from the parent widget as necessary
 *
 * parent: either the menu list widget or a menu entry widget
 * menu: entry to be updated
 */
566
void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
567
{
568 569 570 571 572 573 574
	struct menu* child;
	ConfigItem* item;
	ConfigItem* last;
	bool visible;
	enum prop_type type;

	if (!menu) {
575 576 577 578 579
		while (parent->childCount() > 0)
		{
			delete parent->takeChild(0);
		}

580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
		return;
	}

	last = parent->firstChild();
	if (last && !last->goParent)
		last = 0;
	for (child = menu->list; child; child = child->next) {
		item = last ? last->nextSibling() : parent->firstChild();
		type = child->prompt ? child->prompt->type : P_UNKNOWN;

		switch (mode) {
		case menuMode:
			if (!(child->flags & MENU_ROOT))
				goto hide;
			break;
		case symbolMode:
			if (child->flags & MENU_ROOT)
				goto hide;
			break;
		default:
			break;
		}

		visible = menu_is_visible(child);
		if (!menuSkip(child)) {
			if (!child->sym && !child->list && !child->prompt)
				continue;
			if (!item || item->menu != child)
				item = new ConfigItem(parent, last, child, visible);
			else
				item->testUpdateMenu(visible);

			if (mode == fullMode || mode == menuMode || type != P_MENU)
				updateMenuList(item, child);
			else
				updateMenuList(item, 0);
			last = item;
			continue;
		}
619
hide:
620 621 622 623 624 625 626 627 628
		if (item && item->menu == child) {
			last = parent->firstChild();
			if (last == item)
				last = 0;
			else while (last->nextSibling() != item)
				last = last->nextSibling();
			delete item;
		}
	}
629 630
}

631
void ConfigList::updateMenuList(struct menu *menu)
632 633 634 635 636 637 638 639
{
	struct menu* child;
	ConfigItem* item;
	ConfigItem* last;
	bool visible;
	enum prop_type type;

	if (!menu) {
640
		while (topLevelItemCount() > 0)
641
		{
642
			delete takeTopLevelItem(0);
643 644 645 646 647
		}

		return;
	}

648
	last = (ConfigItem *)topLevelItem(0);
649 650 651
	if (last && !last->goParent)
		last = 0;
	for (child = menu->list; child; child = child->next) {
652
		item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
		type = child->prompt ? child->prompt->type : P_UNKNOWN;

		switch (mode) {
		case menuMode:
			if (!(child->flags & MENU_ROOT))
				goto hide;
			break;
		case symbolMode:
			if (child->flags & MENU_ROOT)
				goto hide;
			break;
		default:
			break;
		}

		visible = menu_is_visible(child);
		if (!menuSkip(child)) {
			if (!child->sym && !child->list && !child->prompt)
				continue;
			if (!item || item->menu != child)
673
				item = new ConfigItem(this, last, child, visible);
674 675 676 677 678 679 680 681 682 683
			else
				item->testUpdateMenu(visible);

			if (mode == fullMode || mode == menuMode || type != P_MENU)
				updateMenuList(item, child);
			else
				updateMenuList(item, 0);
			last = item;
			continue;
		}
684
hide:
685
		if (item && item->menu == child) {
686
			last = (ConfigItem *)topLevelItem(0);
687 688 689 690 691 692 693 694 695
			if (last == item)
				last = 0;
			else while (last->nextSibling() != item)
				last = last->nextSibling();
			delete item;
		}
	}
}

696 697
void ConfigList::keyPressEvent(QKeyEvent* ev)
{
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	QTreeWidgetItem* i = currentItem();
	ConfigItem* item;
	struct menu *menu;
	enum prop_type type;

	if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
		emit parentSelected();
		ev->accept();
		return;
	}

	if (!i) {
		Parent::keyPressEvent(ev);
		return;
	}
	item = (ConfigItem*)i;

	switch (ev->key()) {
	case Qt::Key_Return:
	case Qt::Key_Enter:
		if (item->goParent) {
			emit parentSelected();
			break;
		}
		menu = item->menu;
		if (!menu)
			break;
		type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
		if (type == P_MENU && rootEntry != menu &&
		    mode != fullMode && mode != menuMode) {
728 729 730 731
			if (mode == menuMode)
				emit menuSelected(menu);
			else
				emit itemSelected(menu);
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
			break;
		}
	case Qt::Key_Space:
		changeValue(item);
		break;
	case Qt::Key_N:
		setValue(item, no);
		break;
	case Qt::Key_M:
		setValue(item, mod);
		break;
	case Qt::Key_Y:
		setValue(item, yes);
		break;
	default:
		Parent::keyPressEvent(ev);
		return;
	}
	ev->accept();
751 752
}

753
void ConfigList::mousePressEvent(QMouseEvent* e)
754
{
755 756 757
	//QPoint p(contentsToViewport(e->pos()));
	//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
	Parent::mousePressEvent(e);
758
}
759

760
void ConfigList::mouseReleaseEvent(QMouseEvent* e)
761
{
762 763 764 765 766 767 768 769 770 771 772 773
	QPoint p = e->pos();
	ConfigItem* item = (ConfigItem*)itemAt(p);
	struct menu *menu;
	enum prop_type ptype;
	QIcon icon;
	int idx, x;

	if (!item)
		goto skip;

	menu = item->menu;
	x = header()->offset() + p.x();
774
	idx = header()->logicalIndexAt(x);
775 776 777
	switch (idx) {
	case promptColIdx:
		icon = item->pixmap(promptColIdx);
778 779 780 781 782 783 784 785 786 787
		if (!icon.isNull()) {
			int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
			if (x >= off && x < off + icon.availableSizes().first().width()) {
				if (item->goParent) {
					emit parentSelected();
					break;
				} else if (!menu)
					break;
				ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
				if (ptype == P_MENU && rootEntry != menu &&
788 789
				    mode != fullMode && mode != menuMode &&
                                    mode != listMode)
790 791 792 793 794
					emit menuSelected(menu);
				else
					changeValue(item);
			}
		}
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
		break;
	case noColIdx:
		setValue(item, no);
		break;
	case modColIdx:
		setValue(item, mod);
		break;
	case yesColIdx:
		setValue(item, yes);
		break;
	case dataColIdx:
		changeValue(item);
		break;
	}

skip:
	//printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseReleaseEvent(e);
813 814
}

815
void ConfigList::mouseMoveEvent(QMouseEvent* e)
816
{
817 818 819
	//QPoint p(contentsToViewport(e->pos()));
	//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseMoveEvent(e);
820 821
}

822
void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
823
{
824
	QPoint p = e->pos();
825 826 827 828 829 830 831 832 833 834 835 836 837 838
	ConfigItem* item = (ConfigItem*)itemAt(p);
	struct menu *menu;
	enum prop_type ptype;

	if (!item)
		goto skip;
	if (item->goParent) {
		emit parentSelected();
		goto skip;
	}
	menu = item->menu;
	if (!menu)
		goto skip;
	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
839
	if (ptype == P_MENU && mode != listMode) {
840 841 842 843 844
		if (mode == singleMode)
			emit itemSelected(menu);
		else if (mode == symbolMode)
			emit menuSelected(menu);
	} else if (menu->sym)
845 846 847 848 849
		changeValue(item);

skip:
	//printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseDoubleClickEvent(e);
850 851 852 853
}

void ConfigList::focusInEvent(QFocusEvent *e)
{
854 855 856 857 858 859
	struct menu *menu = NULL;

	Parent::focusInEvent(e);

	ConfigItem* item = (ConfigItem *)currentItem();
	if (item) {
860
		setSelected(item, true);
861 862 863
		menu = item->menu;
	}
	emit gotFocus(menu);
864 865 866 867
}

void ConfigList::contextMenuEvent(QContextMenuEvent *e)
{
868 869 870 871 872
	if (e->y() <= header()->geometry().bottom()) {
		if (!headerPopup) {
			QAction *action;

			headerPopup = new QMenu(this);
873
			action = new QAction("Show Name", this);
874 875 876 877 878 879 880
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowName(bool)));
			  connect(parent(), SIGNAL(showNameChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showName);
			  headerPopup->addAction(action);
881
			action = new QAction("Show Range", this);
882 883 884 885 886 887 888
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowRange(bool)));
			  connect(parent(), SIGNAL(showRangeChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showRange);
			  headerPopup->addAction(action);
889
			action = new QAction("Show Data", this);
890 891 892 893 894 895 896 897 898 899 900 901
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowData(bool)));
			  connect(parent(), SIGNAL(showDataChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showData);
			  headerPopup->addAction(action);
		}
		headerPopup->exec(e->globalPos());
		e->accept();
	} else
		e->ignore();
902 903
}

904 905 906 907
ConfigView*ConfigView::viewList;
QAction *ConfigView::showNormalAction;
QAction *ConfigView::showAllAction;
QAction *ConfigView::showPromptAction;
L
Linus Torvalds 已提交
908

909
ConfigView::ConfigView(QWidget* parent, const char *name)
910
	: Parent(parent)
L
Linus Torvalds 已提交
911
{
912
	setObjectName(name);
913
	QVBoxLayout *verticalLayout = new QVBoxLayout(this);
914
	verticalLayout->setContentsMargins(0, 0, 0, 0);
915

916
	list = new ConfigList(this);
917
	verticalLayout->addWidget(list);
L
Linus Torvalds 已提交
918 919
	lineEdit = new ConfigLineEdit(this);
	lineEdit->hide();
920
	verticalLayout->addWidget(lineEdit);
L
Linus Torvalds 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937

	this->nextView = viewList;
	viewList = this;
}

ConfigView::~ConfigView(void)
{
	ConfigView** vp;

	for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
		if (*vp == this) {
			*vp = nextView;
			break;
		}
	}
}

938
void ConfigView::setOptionMode(QAction *act)
939
{
940 941 942 943 944 945 946 947
	if (act == showNormalAction)
		list->optMode = normalOpt;
	else if (act == showAllAction)
		list->optMode = allOpt;
	else
		list->optMode = promptOpt;

	list->updateListAll();
948 949 950 951
}

void ConfigView::setShowName(bool b)
{
952 953 954 955 956
	if (list->showName != b) {
		list->showName = b;
		list->reinit();
		emit showNameChanged(b);
	}
957 958 959 960
}

void ConfigView::setShowRange(bool b)
{
961 962 963 964 965
	if (list->showRange != b) {
		list->showRange = b;
		list->reinit();
		emit showRangeChanged(b);
	}
966 967 968 969
}

void ConfigView::setShowData(bool b)
{
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
	if (list->showData != b) {
		list->showData = b;
		list->reinit();
		emit showDataChanged(b);
	}
}

void ConfigList::setAllOpen(bool open)
{
	QTreeWidgetItemIterator it(this);

	while (*it) {
		(*it)->setExpanded(open);

		++it;
	}
986 987
}

988
void ConfigView::updateList()
L
Linus Torvalds 已提交
989
{
990 991 992
	ConfigView* v;

	for (v = viewList; v; v = v->nextView)
993
		v->list->updateList();
L
Linus Torvalds 已提交
994 995 996 997
}

void ConfigView::updateListAll(void)
{
998 999 1000 1001
	ConfigView* v;

	for (v = viewList; v; v = v->nextView)
		v->list->updateListAll();
L
Linus Torvalds 已提交
1002 1003
}

1004
ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1005
	: Parent(parent), sym(0), _menu(0)
1006
{
1007
	setObjectName(name);
1008
	setOpenLinks(false);
1009 1010 1011

	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
1012
		setShowDebug(configSettings->value("/showDebug", false).toBool());
1013 1014 1015 1016 1017 1018 1019
		configSettings->endGroup();
		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
	}
}

void ConfigInfoView::saveSettings(void)
{
1020 1021 1022 1023 1024
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/showDebug", showDebug());
		configSettings->endGroup();
	}
1025 1026 1027 1028 1029 1030
}

void ConfigInfoView::setShowDebug(bool b)
{
	if (_showDebug != b) {
		_showDebug = b;
A
Alexander Stein 已提交
1031
		if (_menu)
1032
			menuInfo();
1033 1034
		else if (sym)
			symbolInfo();
1035 1036 1037 1038 1039 1040
		emit showDebugChanged(b);
	}
}

void ConfigInfoView::setInfo(struct menu *m)
{
A
Alexander Stein 已提交
1041
	if (_menu == m)
1042
		return;
A
Alexander Stein 已提交
1043
	_menu = m;
1044
	sym = NULL;
A
Alexander Stein 已提交
1045
	if (!_menu)
1046
		clear();
1047
	else
1048 1049 1050
		menuInfo();
}

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
void ConfigInfoView::symbolInfo(void)
{
	QString str;

	str += "<big>Symbol: <b>";
	str += print_filter(sym->name);
	str += "</b></big><br><br>value: ";
	str += print_filter(sym_get_string_value(sym));
	str += "<br>visibility: ";
	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
	str += "<br>";
	str += debug_info(sym);

	setText(str);
}

1067 1068 1069 1070 1071
void ConfigInfoView::menuInfo(void)
{
	struct symbol* sym;
	QString head, debug, help;

A
Alexander Stein 已提交
1072
	sym = _menu->sym;
1073
	if (sym) {
A
Alexander Stein 已提交
1074
		if (_menu->prompt) {
1075
			head += "<big><b>";
1076
			head += print_filter(_menu->prompt->text);
1077 1078 1079
			head += "</b></big>";
			if (sym->name) {
				head += " (";
1080
				if (showDebug())
1081
					head += QString().sprintf("<a href=\"s%s\">", sym->name);
1082
				head += print_filter(sym->name);
1083 1084
				if (showDebug())
					head += "</a>";
1085 1086 1087 1088
				head += ")";
			}
		} else if (sym->name) {
			head += "<big><b>";
1089
			if (showDebug())
1090
				head += QString().sprintf("<a href=\"s%s\">", sym->name);
1091
			head += print_filter(sym->name);
1092 1093
			if (showDebug())
				head += "</a>";
1094 1095 1096 1097 1098 1099 1100
			head += "</b></big>";
		}
		head += "<br><br>";

		if (showDebug())
			debug = debug_info(sym);

1101
		struct gstr help_gstr = str_new();
A
Alexander Stein 已提交
1102
		menu_get_ext_help(_menu, &help_gstr);
1103 1104
		help = print_filter(str_get(&help_gstr));
		str_free(&help_gstr);
A
Alexander Stein 已提交
1105
	} else if (_menu->prompt) {
1106
		head += "<big><b>";
1107
		head += print_filter(_menu->prompt->text);
1108 1109
		head += "</b></big><br><br>";
		if (showDebug()) {
A
Alexander Stein 已提交
1110
			if (_menu->prompt->visible.expr) {
1111
				debug += "&nbsp;&nbsp;dep: ";
A
Alexander Stein 已提交
1112
				expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1113 1114 1115 1116 1117
				debug += "<br><br>";
			}
		}
	}
	if (showDebug())
A
Alexander Stein 已提交
1118
		debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140

	setText(head + debug + help);
}

QString ConfigInfoView::debug_info(struct symbol *sym)
{
	QString debug;

	debug += "type: ";
	debug += print_filter(sym_type_name(sym->type));
	if (sym_is_choice(sym))
		debug += " (choice)";
	debug += "<br>";
	if (sym->rev_dep.expr) {
		debug += "reverse dep: ";
		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
		debug += "<br>";
	}
	for (struct property *prop = sym->prop; prop; prop = prop->next) {
		switch (prop->type) {
		case P_PROMPT:
		case P_MENU:
1141
			debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1142
			debug += print_filter(prop->text);
1143
			debug += "</a><br>";
1144 1145
			break;
		case P_DEFAULT:
1146 1147
		case P_SELECT:
		case P_RANGE:
1148 1149 1150
		case P_COMMENT:
		case P_IMPLY:
		case P_SYMBOL:
1151 1152
			debug += prop_get_type_name(prop->type);
			debug += ": ";
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
			debug += "<br>";
			break;
		case P_CHOICE:
			if (sym_is_choice(sym)) {
				debug += "choice: ";
				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
				debug += "<br>";
			}
			break;
		default:
			debug += "unknown property: ";
			debug += prop_get_type_name(prop->type);
			debug += "<br>";
		}
		if (prop->visible.expr) {
			debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
			debug += "<br>";
		}
	}
	debug += "<br>";

	return debug;
}

QString ConfigInfoView::print_filter(const QString &str)
{
	QRegExp re("[<>&\"\\n]");
	QString res = str;
1183 1184
	for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
		switch (res[i].toLatin1()) {
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
		case '<':
			res.replace(i, 1, "&lt;");
			i += 4;
			break;
		case '>':
			res.replace(i, 1, "&gt;");
			i += 4;
			break;
		case '&':
			res.replace(i, 1, "&amp;");
			i += 5;
			break;
		case '"':
			res.replace(i, 1, "&quot;");
			i += 6;
			break;
		case '\n':
			res.replace(i, 1, "<br>");
			i += 4;
			break;
		}
	}
	return res;
}

1210
void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1211
{
1212 1213 1214 1215
	QString* text = reinterpret_cast<QString*>(data);
	QString str2 = print_filter(str);

	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1216
		*text += QString().sprintf("<a href=\"s%s\">", sym->name);
1217 1218 1219 1220
		*text += str2;
		*text += "</a>";
	} else
		*text += str2;
1221 1222
}

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
void ConfigInfoView::clicked(const QUrl &url)
{
	QByteArray str = url.toEncoded();
	const std::size_t count = str.size();
	char *data = new char[count + 1];
	struct symbol **result;
	struct menu *m = NULL;

	if (count < 1) {
		qInfo() << "Clicked link is empty";
1233
		delete[] data;
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
		return;
	}

	memcpy(data, str.constData(), count);
	data[count] = '\0';

	/* Seek for exact match */
	data[0] = '^';
	strcat(data, "$");
	result = sym_re_search(data);
	if (!result) {
		qInfo() << "Clicked symbol is invalid:" << data;
1246
		delete[] data;
1247 1248 1249 1250 1251
		return;
	}

	sym = *result;

1252
	/* Seek for the menu which holds the symbol */
1253 1254 1255 1256 1257 1258 1259 1260
	for (struct property *prop = sym->prop; prop; prop = prop->next) {
		    if (prop->type != P_PROMPT && prop->type != P_MENU)
			    continue;
		    m = prop->menu;
		    break;
	}

	if (!m) {
1261 1262 1263 1264 1265
		/* Symbol is not visible as a menu */
		symbolInfo();
		emit showDebugChanged(true);
	} else {
		emit menuSelected(m);
1266 1267 1268 1269 1270 1271
	}

	free(result);
	delete data;
}

1272
QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1273
{
1274
	QMenu* popup = Parent::createStandardContextMenu(pos);
1275
	QAction* action = new QAction("Show Debug Info", popup);
1276 1277 1278 1279 1280

	action->setCheckable(true);
	connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
	connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
	action->setChecked(showDebug());
1281
	popup->addSeparator();
1282
	popup->addAction(action);
1283 1284 1285
	return popup;
}

1286
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1287
{
1288
	Parent::contextMenuEvent(e);
1289 1290
}

1291
ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1292
	: Parent(parent), result(NULL)
1293
{
1294
	setObjectName("search");
1295
	setWindowTitle("Search Config");
1296

1297 1298 1299
	QVBoxLayout* layout1 = new QVBoxLayout(this);
	layout1->setContentsMargins(11, 11, 11, 11);
	layout1->setSpacing(6);
1300 1301

	QHBoxLayout* layout2 = new QHBoxLayout();
1302 1303
	layout2->setContentsMargins(0, 0, 0, 0);
	layout2->setSpacing(6);
1304
	layout2->addWidget(new QLabel("Find:", this));
1305 1306 1307
	editField = new QLineEdit(this);
	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
	layout2->addWidget(editField);
1308
	searchButton = new QPushButton("Search", this);
1309
	searchButton->setAutoDefault(false);
1310 1311 1312 1313
	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
	layout2->addWidget(searchButton);
	layout1->addLayout(layout2);

1314
	split = new QSplitter(this);
1315
	split->setOrientation(Qt::Vertical);
1316
	list = new ConfigView(split, "search");
1317
	list->list->mode = listMode;
1318
	info = new ConfigInfoView(split, "search");
1319 1320
	connect(list->list, SIGNAL(menuChanged(struct menu *)),
		info, SLOT(setInfo(struct menu *)));
1321 1322 1323
	connect(list->list, SIGNAL(menuChanged(struct menu *)),
		parent, SLOT(setMenuLink(struct menu *)));

1324
	layout1->addWidget(split);
1325

1326 1327 1328
	QVariant x, y;
	int width, height;
	bool ok;
1329

1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
	configSettings->beginGroup("search");
	width = configSettings->value("/window width", parent->width() / 2).toInt();
	height = configSettings->value("/window height", parent->height() / 2).toInt();
	resize(width, height);
	x = configSettings->value("/window x");
	y = configSettings->value("/window y");
	if (x.isValid() && y.isValid())
		move(x.toInt(), y.toInt());
	QList<int> sizes = configSettings->readSizes("/split", &ok);
	if (ok)
		split->setSizes(sizes);
	configSettings->endGroup();
	connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1343 1344 1345 1346
}

void ConfigSearchWindow::saveSettings(void)
{
1347 1348 1349 1350 1351 1352 1353 1354 1355
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/window x", pos().x());
		configSettings->setValue("/window y", pos().y());
		configSettings->setValue("/window width", size().width());
		configSettings->setValue("/window height", size().height());
		configSettings->writeSizes("/split", split->sizes());
		configSettings->endGroup();
	}
1356 1357 1358 1359
}

void ConfigSearchWindow::search(void)
{
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
	struct symbol **p;
	struct property *prop;
	ConfigItem *lastItem = NULL;

	free(result);
	list->list->clear();
	info->clear();

	result = sym_re_search(editField->text().toLatin1());
	if (!result)
		return;
	for (p = result; *p; p++) {
		for_all_prompts((*p), prop)
			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
						  menu_is_visible(prop->menu));
	}
1376 1377
}

L
Linus Torvalds 已提交
1378 1379 1380 1381
/*
 * Construct the complete config widget
 */
ConfigMainWindow::ConfigMainWindow(void)
1382
	: searchWindow(0)
L
Linus Torvalds 已提交
1383
{
1384
	bool ok = true;
1385 1386
	QVariant x, y;
	int width, height;
R
Randy Dunlap 已提交
1387
	char title[256];
L
Linus Torvalds 已提交
1388

1389
	QDesktopWidget *d = configApp->desktop();
1390 1391
	snprintf(title, sizeof(title), "%s%s",
		rootmenu.prompt->text,
1392 1393
		""
		);
1394
	setWindowTitle(title);
L
Linus Torvalds 已提交
1395

1396 1397
	width = configSettings->value("/window width", d->width() - 64).toInt();
	height = configSettings->value("/window height", d->height() - 64).toInt();
L
Linus Torvalds 已提交
1398
	resize(width, height);
1399 1400 1401 1402
	x = configSettings->value("/window x");
	y = configSettings->value("/window y");
	if ((x.isValid())&&(y.isValid()))
		move(x.toInt(), y.toInt());
L
Linus Torvalds 已提交
1403

1404 1405 1406 1407 1408
	QWidget *widget = new QWidget(this);
	QVBoxLayout *layout = new QVBoxLayout(widget);
	setCentralWidget(widget);

	split1 = new QSplitter(widget);
1409
	split1->setOrientation(Qt::Horizontal);
1410
	split1->setChildrenCollapsible(false);
L
Linus Torvalds 已提交
1411

1412
	menuView = new ConfigView(widget, "menu");
L
Linus Torvalds 已提交
1413 1414
	menuList = menuView->list;

1415 1416
	split2 = new QSplitter(widget);
	split2->setChildrenCollapsible(false);
1417
	split2->setOrientation(Qt::Vertical);
L
Linus Torvalds 已提交
1418 1419

	// create config tree
1420
	configView = new ConfigView(widget, "config");
L
Linus Torvalds 已提交
1421 1422
	configList = configView->list;

1423 1424 1425 1426 1427 1428 1429
	helpText = new ConfigInfoView(widget, "help");

	layout->addWidget(split2);
	split2->addWidget(split1);
	split1->addWidget(configView);
	split1->addWidget(menuView);
	split2->addWidget(helpText);
L
Linus Torvalds 已提交
1430 1431 1432 1433

	setTabOrder(configList, helpText);
	configList->setFocus();

1434
	backAction = new QAction(QPixmap(xpm_back), "Back", this);
1435 1436
	connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));

1437
	QAction *quitAction = new QAction("&Quit", this);
1438
	quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1439 1440
	connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));

1441
	QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1442
	loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1443 1444
	connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));

1445
	saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1446
	saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1447 1448
	connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));

1449
	conf_set_changed_callback(conf_changed);
1450

1451 1452
	// Set saveAction's initial state
	conf_changed();
1453 1454
	configname = xstrdup(conf_get_configname());

1455
	QAction *saveAsAction = new QAction("Save &As...", this);
1456
	  connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1457
	QAction *searchAction = new QAction("&Find", this);
1458
	searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1459
	  connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1460
	singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1461
	singleViewAction->setCheckable(true);
1462
	  connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1463
	splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1464
	splitViewAction->setCheckable(true);
1465
	  connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1466
	fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1467
	fullViewAction->setCheckable(true);
1468
	  connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
L
Linus Torvalds 已提交
1469

1470
	QAction *showNameAction = new QAction("Show Name", this);
1471
	  showNameAction->setCheckable(true);
1472
	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1473
	  showNameAction->setChecked(configView->showName());
1474
	QAction *showRangeAction = new QAction("Show Range", this);
1475
	  showRangeAction->setCheckable(true);
1476
	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1477
	QAction *showDataAction = new QAction("Show Data", this);
1478
	  showDataAction->setCheckable(true);
1479
	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1480 1481

	QActionGroup *optGroup = new QActionGroup(this);
1482
	optGroup->setExclusive(true);
1483
	connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1484
		SLOT(setOptionMode(QAction *)));
1485
	connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1486 1487
		SLOT(setOptionMode(QAction *)));

1488 1489 1490
	configView->showNormalAction = new QAction("Show Normal Options", optGroup);
	configView->showAllAction = new QAction("Show All Options", optGroup);
	configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1491 1492 1493
	configView->showNormalAction->setCheckable(true);
	configView->showAllAction->setCheckable(true);
	configView->showPromptAction->setCheckable(true);
1494

1495
	QAction *showDebugAction = new QAction("Show Debug Info", this);
1496
	  showDebugAction->setCheckable(true);
1497
	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1498
	  showDebugAction->setChecked(helpText->showDebug());
L
Linus Torvalds 已提交
1499

1500
	QAction *showIntroAction = new QAction("Introduction", this);
1501
	  connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1502
	QAction *showAboutAction = new QAction("About", this);
1503
	  connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
L
Linus Torvalds 已提交
1504 1505

	// init tool bar
1506
	QToolBar *toolBar = addToolBar("Tools");
1507
	toolBar->addAction(backAction);
L
Linus Torvalds 已提交
1508
	toolBar->addSeparator();
1509 1510
	toolBar->addAction(loadAction);
	toolBar->addAction(saveAction);
L
Linus Torvalds 已提交
1511
	toolBar->addSeparator();
1512 1513 1514
	toolBar->addAction(singleViewAction);
	toolBar->addAction(splitViewAction);
	toolBar->addAction(fullViewAction);
L
Linus Torvalds 已提交
1515

1516 1517 1518 1519 1520 1521 1522
	// create file menu
	QMenu *menu = menuBar()->addMenu("&File");
	menu->addAction(loadAction);
	menu->addAction(saveAction);
	menu->addAction(saveAsAction);
	menu->addSeparator();
	menu->addAction(quitAction);
L
Linus Torvalds 已提交
1523

1524
	// create edit menu
1525 1526
	menu = menuBar()->addMenu("&Edit");
	menu->addAction(searchAction);
1527

L
Linus Torvalds 已提交
1528
	// create options menu
1529 1530 1531 1532 1533 1534 1535 1536
	menu = menuBar()->addMenu("&Option");
	menu->addAction(showNameAction);
	menu->addAction(showRangeAction);
	menu->addAction(showDataAction);
	menu->addSeparator();
	menu->addActions(optGroup->actions());
	menu->addSeparator();
	menu->addAction(showDebugAction);
L
Linus Torvalds 已提交
1537 1538

	// create help menu
1539 1540 1541
	menu = menuBar()->addMenu("&Help");
	menu->addAction(showIntroAction);
	menu->addAction(showAboutAction);
L
Linus Torvalds 已提交
1542

1543 1544 1545
	connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
		 helpText, SLOT (clicked (const QUrl &)) );

1546 1547 1548 1549
	connect(configList, SIGNAL(menuChanged(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(configList, SIGNAL(menuSelected(struct menu *)),
		SLOT(changeMenu(struct menu *)));
1550 1551
	connect(configList, SIGNAL(itemSelected(struct menu *)),
		SLOT(changeItens(struct menu *)));
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
	connect(configList, SIGNAL(parentSelected()),
		SLOT(goBack()));
	connect(menuList, SIGNAL(menuChanged(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(menuSelected(struct menu *)),
		SLOT(changeMenu(struct menu *)));

	connect(configList, SIGNAL(gotFocus(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(gotFocus(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(gotFocus(struct menu *)),
		SLOT(listFocusChanged(void)));
1565 1566
	connect(helpText, SIGNAL(menuSelected(struct menu *)),
		SLOT(setMenuLink(struct menu *)));
L
Linus Torvalds 已提交
1567

1568
	QString listMode = configSettings->value("/listMode", "symbol").toString();
L
Linus Torvalds 已提交
1569 1570 1571 1572 1573 1574 1575 1576
	if (listMode == "single")
		showSingleView();
	else if (listMode == "full")
		showFullView();
	else /*if (listMode == "split")*/
		showSplitView();

	// UI setup done, restore splitter positions
1577
	QList<int> sizes = configSettings->readSizes("/split1", &ok);
L
Linus Torvalds 已提交
1578 1579 1580
	if (ok)
		split1->setSizes(sizes);

1581
	sizes = configSettings->readSizes("/split2", &ok);
L
Linus Torvalds 已提交
1582 1583 1584 1585 1586 1587
	if (ok)
		split2->setSizes(sizes);
}

void ConfigMainWindow::loadConfig(void)
{
1588 1589 1590 1591 1592 1593
	QString str;
	QByteArray ba;
	const char *name;

	str = QFileDialog::getOpenFileName(this, "", configname);
	if (str.isNull())
L
Linus Torvalds 已提交
1594
		return;
1595 1596 1597 1598 1599

	ba = str.toLocal8Bit();
	name = ba.data();

	if (conf_read(name))
1600
		QMessageBox::information(this, "qconf", "Unable to load configuration!");
1601 1602 1603 1604

	free(configname);
	configname = xstrdup(name);

L
Linus Torvalds 已提交
1605 1606 1607
	ConfigView::updateListAll();
}

1608
bool ConfigMainWindow::saveConfig(void)
L
Linus Torvalds 已提交
1609
{
1610
	if (conf_write(configname)) {
1611
		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1612 1613
		return false;
	}
1614 1615
	conf_write_autoconf(0);

1616
	return true;
L
Linus Torvalds 已提交
1617 1618 1619 1620
}

void ConfigMainWindow::saveConfigAs(void)
{
1621 1622 1623 1624 1625 1626
	QString str;
	QByteArray ba;
	const char *name;

	str = QFileDialog::getSaveFileName(this, "", configname);
	if (str.isNull())
L
Linus Torvalds 已提交
1627
		return;
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638

	ba = str.toLocal8Bit();
	name = ba.data();

	if (conf_write(name)) {
		QMessageBox::information(this, "qconf", "Unable to save configuration!");
	}
	conf_write_autoconf(0);

	free(configname);
	configname = xstrdup(name);
L
Linus Torvalds 已提交
1639 1640
}

1641 1642 1643
void ConfigMainWindow::searchConfig(void)
{
	if (!searchWindow)
1644
		searchWindow = new ConfigSearchWindow(this);
1645 1646 1647
	searchWindow->show();
}

1648
void ConfigMainWindow::changeItens(struct menu *menu)
L
Linus Torvalds 已提交
1649
{
1650
	configList->setRootMenu(menu);
L
Linus Torvalds 已提交
1651 1652
}

1653 1654 1655 1656 1657
void ConfigMainWindow::changeMenu(struct menu *menu)
{
	menuList->setRootMenu(menu);
}

1658
void ConfigMainWindow::setMenuLink(struct menu *menu)
L
Linus Torvalds 已提交
1659
{
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
	struct menu *parent;
	ConfigList* list = NULL;
	ConfigItem* item;

	if (configList->menuSkip(menu))
		return;

	switch (configList->mode) {
	case singleMode:
		list = configList;
		parent = menu_get_parent_menu(menu);
		if (!parent)
			return;
		list->setRootMenu(parent);
		break;
1675
	case menuMode:
1676
		if (menu->flags & MENU_ROOT) {
1677
			menuList->setRootMenu(menu);
1678 1679
			configList->clearSelection();
			list = configList;
1680
		} else {
1681 1682 1683
			parent = menu_get_parent_menu(menu->parent);
			if (!parent)
				return;
1684 1685 1686

			/* Select the config view */
			item = configList->findConfigItem(parent);
1687
			if (item) {
1688
				configList->setSelected(item, true);
1689
				configList->scrollToItem(item);
1690
			}
1691 1692 1693 1694

			menuList->setRootMenu(parent);
			menuList->clearSelection();
			list = menuList;
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
		}
		break;
	case fullMode:
		list = configList;
		break;
	default:
		break;
	}

	if (list) {
		item = list->findConfigItem(menu);
		if (item) {
1707
			list->setSelected(item, true);
1708 1709
			list->scrollToItem(item);
			list->setFocus();
1710
			helpText->setInfo(menu);
1711 1712
		}
	}
L
Linus Torvalds 已提交
1713 1714
}

1715 1716
void ConfigMainWindow::listFocusChanged(void)
{
1717 1718
	if (menuList->mode == menuMode)
		configList->clearSelection();
1719 1720
}

L
Linus Torvalds 已提交
1721 1722
void ConfigMainWindow::goBack(void)
{
1723
	if (configList->rootEntry == &rootmenu)
B
Boris Barbulovski 已提交
1724 1725
		return;

1726
	configList->setParentMenu();
L
Linus Torvalds 已提交
1727 1728 1729 1730
}

void ConfigMainWindow::showSingleView(void)
{
1731 1732 1733 1734 1735 1736 1737
	singleViewAction->setEnabled(false);
	singleViewAction->setChecked(true);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1738 1739
	backAction->setEnabled(true);

L
Linus Torvalds 已提交
1740
	menuView->hide();
1741 1742 1743 1744 1745 1746
	menuList->setRootMenu(0);
	configList->mode = singleMode;
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
L
Linus Torvalds 已提交
1747 1748 1749 1750 1751
	configList->setFocus();
}

void ConfigMainWindow::showSplitView(void)
{
1752 1753 1754 1755 1756 1757 1758
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(false);
	splitViewAction->setChecked(true);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1759 1760
	backAction->setEnabled(false);

1761
	configList->mode = menuMode;
1762 1763 1764 1765 1766 1767
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
	configList->setAllOpen(true);
	configApp->processEvents();
1768
	menuList->mode = symbolMode;
1769 1770
	menuList->setRootMenu(&rootmenu);
	menuList->setAllOpen(true);
L
Linus Torvalds 已提交
1771 1772 1773 1774 1775 1776
	menuView->show();
	menuList->setFocus();
}

void ConfigMainWindow::showFullView(void)
{
1777 1778 1779 1780 1781 1782 1783
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(false);
	fullViewAction->setChecked(true);

1784 1785
	backAction->setEnabled(false);

L
Linus Torvalds 已提交
1786
	menuView->hide();
1787 1788 1789 1790 1791 1792
	menuList->setRootMenu(0);
	configList->mode = fullMode;
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
L
Linus Torvalds 已提交
1793 1794 1795 1796 1797 1798 1799 1800
	configList->setFocus();
}

/*
 * ask for saving configuration before quitting
 */
void ConfigMainWindow::closeEvent(QCloseEvent* e)
{
1801
	if (!conf_get_changed()) {
L
Linus Torvalds 已提交
1802 1803 1804
		e->accept();
		return;
	}
1805
	QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
L
Linus Torvalds 已提交
1806
			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1807 1808 1809
	mb.setButtonText(QMessageBox::Yes, "&Save Changes");
	mb.setButtonText(QMessageBox::No, "&Discard Changes");
	mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
L
Linus Torvalds 已提交
1810 1811
	switch (mb.exec()) {
	case QMessageBox::Yes:
1812 1813 1814 1815 1816
		if (saveConfig())
			e->accept();
		else
			e->ignore();
		break;
L
Linus Torvalds 已提交
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
	case QMessageBox::No:
		e->accept();
		break;
	case QMessageBox::Cancel:
		e->ignore();
		break;
	}
}

void ConfigMainWindow::showIntro(void)
{
1828
	static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
L
Linus Torvalds 已提交
1829 1830 1831 1832 1833 1834 1835 1836 1837
		"For each option, a blank box indicates the feature is disabled, a check\n"
		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
		"as a module.  Clicking on the box will cycle through the three states.\n\n"
		"If you do not see an option (e.g., a device driver) that you believe\n"
		"should be present, try turning on Show All Options under the Options menu.\n"
		"Although there is no cross reference yet to help you figure out what other\n"
		"options must be enabled to support the option you are interested in, you can\n"
		"still view the help of a grayed-out option.\n\n"
		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1838
		"which you can then match by examining other options.\n\n";
L
Linus Torvalds 已提交
1839 1840 1841 1842 1843 1844

	QMessageBox::information(this, "qconf", str);
}

void ConfigMainWindow::showAbout(void)
{
1845
	static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1846
		"Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1847
		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
L
Linus Torvalds 已提交
1848 1849 1850 1851 1852 1853

	QMessageBox::information(this, "qconf", str);
}

void ConfigMainWindow::saveSettings(void)
{
1854 1855 1856 1857
	configSettings->setValue("/window x", pos().x());
	configSettings->setValue("/window y", pos().y());
	configSettings->setValue("/window width", size().width());
	configSettings->setValue("/window height", size().height());
L
Linus Torvalds 已提交
1858 1859

	QString entry;
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
	switch(configList->mode) {
	case singleMode :
		entry = "single";
		break;

	case symbolMode :
		entry = "split";
		break;

	case fullMode :
		entry = "full";
		break;
1872

1873 1874 1875
	default:
		break;
	}
1876
	configSettings->setValue("/listMode", entry);
L
Linus Torvalds 已提交
1877

1878 1879
	configSettings->writeSizes("/split1", split1->sizes());
	configSettings->writeSizes("/split2", split2->sizes());
L
Linus Torvalds 已提交
1880 1881
}

1882 1883 1884 1885 1886 1887
void ConfigMainWindow::conf_changed(void)
{
	if (saveAction)
		saveAction->setEnabled(conf_get_changed());
}

L
Linus Torvalds 已提交
1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
void fixup_rootmenu(struct menu *menu)
{
	struct menu *child;
	static int menu_cnt = 0;

	menu->flags |= MENU_ROOT;
	for (child = menu->list; child; child = child->next) {
		if (child->prompt && child->prompt->type == P_MENU) {
			menu_cnt++;
			fixup_rootmenu(child);
			menu_cnt--;
		} else if (!menu_cnt)
			fixup_rootmenu(child);
	}
}

static const char *progname;

static void usage(void)
{
1908
	printf("%s [-s] <config>\n", progname);
L
Linus Torvalds 已提交
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920
	exit(0);
}

int main(int ac, char** av)
{
	ConfigMainWindow* v;
	const char *name;

	progname = av[0];
	configApp = new QApplication(ac, av);
	if (ac > 1 && av[1][0] == '-') {
		switch (av[1][1]) {
1921 1922 1923
		case 's':
			conf_set_message_callback(NULL);
			break;
L
Linus Torvalds 已提交
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938
		case 'h':
		case '?':
			usage();
		}
		name = av[2];
	} else
		name = av[1];
	if (!name)
		usage();

	conf_parse(name);
	fixup_rootmenu(&rootmenu);
	conf_read(NULL);
	//zconfdump(stdout);

1939 1940
	configSettings = new ConfigSettings();
	configSettings->beginGroup("/kconfig/qconf");
L
Linus Torvalds 已提交
1941 1942 1943 1944 1945
	v = new ConfigMainWindow();

	//zconfdump(stdout);
	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1946
	v->show();
L
Linus Torvalds 已提交
1947 1948
	configApp->exec();

1949 1950
	configSettings->endGroup();
	delete configSettings;
1951 1952
	delete v;
	delete configApp;
1953

L
Linus Torvalds 已提交
1954 1955
	return 0;
}