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