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