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