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