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