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