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