qconf.cc 45.3 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());
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291 292 293
		parent()->updateList(item);
		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 408
}

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

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

		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 449 450
		return;
	}
update:
	updateMenuList(this, rootEntry);
	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 474 475 476
	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);
		parent()->updateList(item);
		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 508 509 510 511 512
	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)
			parent()->updateList(item);
		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 527 528 529 530
	enum prop_type type;

	if (rootEntry == menu)
		return;
	type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
	if (type != P_MENU)
		return;
	updateMenuList(this, 0);
	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 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
{
	struct menu* child;
	ConfigItem* item;
	ConfigItem* last;
	bool visible;
	enum prop_type type;

	if (!menu) {
		while (parent->topLevelItemCount() > 0)
		{
			delete parent->takeTopLevelItem(0);
		}

		return;
	}

	last = (ConfigItem*)parent->topLevelItem(0);
	if (last && !last->goParent)
		last = 0;
	for (child = menu->list; child; child = child->next) {
		item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
		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;
		}
684
hide:
685 686 687 688 689 690 691 692 693 694 695
		if (item && item->menu == child) {
			last = (ConfigItem*)parent->topLevelItem(0);
			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(ConfigItem* item)
L
Linus Torvalds 已提交
989
{
990 991 992 993
	ConfigView* v;

	for (v = viewList; v; v = v->nextView)
		v->list->updateList(item);
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, const char *name)
1292
	: Parent(parent), result(NULL)
1293
{
1294
	setObjectName(name);
1295
	setWindowTitle("Search Config");
1296

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

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

1323
	layout1->addWidget(split);
1324 1325

	if (name) {
1326 1327
		QVariant x, y;
		int width, height;
1328 1329 1330
		bool ok;

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

void ConfigSearchWindow::saveSettings(void)
{
1348 1349 1350 1351 1352 1353 1354 1355 1356
	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();
	}
1357 1358 1359 1360
}

void ConfigSearchWindow::search(void)
{
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376
	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));
	}
1377 1378
}

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

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

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

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

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

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

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

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

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

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

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

1435
	QToolBar *toolBar = new QToolBar("Tools", this);
1436
	addToolBar(toolBar);
L
Linus Torvalds 已提交
1437

1438
	backAction = new QAction(QPixmap(xpm_back), "Back", this);
1439 1440
	connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));

1441
	QAction *quitAction = new QAction("&Quit", this);
1442
	quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1443 1444
	connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));

1445
	QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1446
	loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1447 1448
	connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));

1449
	saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1450
	saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1451 1452
	connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));

1453
	conf_set_changed_callback(conf_changed);
1454

1455 1456
	// Set saveAction's initial state
	conf_changed();
1457 1458
	configname = xstrdup(conf_get_configname());

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

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

	QActionGroup *optGroup = new QActionGroup(this);
1486
	optGroup->setExclusive(true);
1487
	connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1488
		SLOT(setOptionMode(QAction *)));
1489
	connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1490 1491
		SLOT(setOptionMode(QAction *)));

1492 1493 1494
	configView->showNormalAction = new QAction("Show Normal Options", optGroup);
	configView->showAllAction = new QAction("Show All Options", optGroup);
	configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1495 1496 1497
	configView->showNormalAction->setCheckable(true);
	configView->showAllAction->setCheckable(true);
	configView->showPromptAction->setCheckable(true);
1498

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

1504
	QAction *showIntroAction = new QAction("Introduction", this);
1505
	  connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1506
	QAction *showAboutAction = new QAction("About", this);
1507
	  connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
L
Linus Torvalds 已提交
1508 1509

	// init tool bar
1510
	toolBar->addAction(backAction);
L
Linus Torvalds 已提交
1511
	toolBar->addSeparator();
1512 1513
	toolBar->addAction(loadAction);
	toolBar->addAction(saveAction);
L
Linus Torvalds 已提交
1514
	toolBar->addSeparator();
1515 1516 1517
	toolBar->addAction(singleViewAction);
	toolBar->addAction(splitViewAction);
	toolBar->addAction(fullViewAction);
L
Linus Torvalds 已提交
1518

1519 1520 1521 1522 1523 1524 1525
	// 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 已提交
1526

1527
	// create edit menu
1528 1529
	menu = menuBar()->addMenu("&Edit");
	menu->addAction(searchAction);
1530

L
Linus Torvalds 已提交
1531
	// create options menu
1532 1533 1534 1535 1536 1537 1538 1539
	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 已提交
1540 1541

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

1546 1547 1548
	connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
		 helpText, SLOT (clicked (const QUrl &)) );

1549 1550 1551 1552
	connect(configList, SIGNAL(menuChanged(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(configList, SIGNAL(menuSelected(struct menu *)),
		SLOT(changeMenu(struct menu *)));
1553 1554
	connect(configList, SIGNAL(itemSelected(struct menu *)),
		SLOT(changeItens(struct menu *)));
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
	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)));
1568 1569
	connect(helpText, SIGNAL(menuSelected(struct menu *)),
		SLOT(setMenuLink(struct menu *)));
L
Linus Torvalds 已提交
1570

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

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

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

void ConfigMainWindow::loadConfig(void)
{
1591 1592 1593 1594 1595 1596
	QString str;
	QByteArray ba;
	const char *name;

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

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

	if (conf_read(name))
1603
		QMessageBox::information(this, "qconf", "Unable to load configuration!");
1604 1605 1606 1607

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

L
Linus Torvalds 已提交
1608 1609 1610
	ConfigView::updateListAll();
}

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

1619
	return true;
L
Linus Torvalds 已提交
1620 1621 1622 1623
}

void ConfigMainWindow::saveConfigAs(void)
{
1624 1625 1626 1627 1628 1629
	QString str;
	QByteArray ba;
	const char *name;

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

	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 已提交
1642 1643
}

1644 1645 1646
void ConfigMainWindow::searchConfig(void)
{
	if (!searchWindow)
1647
		searchWindow = new ConfigSearchWindow(this, "search");
1648 1649 1650
	searchWindow->show();
}

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

1656 1657 1658 1659 1660
void ConfigMainWindow::changeMenu(struct menu *menu)
{
	menuList->setRootMenu(menu);
}

1661
void ConfigMainWindow::setMenuLink(struct menu *menu)
L
Linus Torvalds 已提交
1662
{
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
	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;
1678
	case menuMode:
1679
		if (menu->flags & MENU_ROOT) {
1680
			menuList->setRootMenu(menu);
1681 1682
			configList->clearSelection();
			list = configList;
1683
		} else {
1684 1685 1686
			parent = menu_get_parent_menu(menu->parent);
			if (!parent)
				return;
1687 1688 1689

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

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

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

1718 1719
void ConfigMainWindow::listFocusChanged(void)
{
1720 1721
	if (menuList->mode == menuMode)
		configList->clearSelection();
1722 1723
}

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

1729
	configList->setParentMenu();
L
Linus Torvalds 已提交
1730 1731 1732 1733
}

void ConfigMainWindow::showSingleView(void)
{
1734 1735 1736 1737 1738 1739 1740
	singleViewAction->setEnabled(false);
	singleViewAction->setChecked(true);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1741 1742
	backAction->setEnabled(true);

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

void ConfigMainWindow::showSplitView(void)
{
1755 1756 1757 1758 1759 1760 1761
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(false);
	splitViewAction->setChecked(true);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1762 1763
	backAction->setEnabled(false);

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

void ConfigMainWindow::showFullView(void)
{
1780 1781 1782 1783 1784 1785 1786
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(false);
	fullViewAction->setChecked(true);

1787 1788
	backAction->setEnabled(false);

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

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

void ConfigMainWindow::showIntro(void)
{
1831
	static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
L
Linus Torvalds 已提交
1832 1833 1834 1835 1836 1837 1838 1839 1840
		"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"
1841
		"which you can then match by examining other options.\n\n";
L
Linus Torvalds 已提交
1842 1843 1844 1845 1846 1847

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

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

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

void ConfigMainWindow::saveSettings(void)
{
1857 1858 1859 1860
	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 已提交
1861 1862

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

	case symbolMode :
		entry = "split";
		break;

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

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

1881 1882
	configSettings->writeSizes("/split1", split1->sizes());
	configSettings->writeSizes("/split2", split2->sizes());
L
Linus Torvalds 已提交
1883 1884
}

1885 1886 1887 1888 1889 1890
void ConfigMainWindow::conf_changed(void)
{
	if (saveAction)
		saveAction->setEnabled(conf_get_changed());
}

L
Linus Torvalds 已提交
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910
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)
{
1911
	printf("%s [-s] <config>\n", progname);
L
Linus Torvalds 已提交
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923
	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]) {
1924 1925 1926
		case 's':
			conf_set_message_callback(NULL);
			break;
L
Linus Torvalds 已提交
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
		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);

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

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

1952 1953
	configSettings->endGroup();
	delete configSettings;
1954 1955
	delete v;
	delete configApp;
1956

L
Linus Torvalds 已提交
1957 1958
	return 0;
}