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