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