busybox/scripts/kconfig/qconf.cc
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
   3 * Released under the terms of the GNU GPL v2.0.
   4 */
   5
   6#include <qapplication.h>
   7#include <qmainwindow.h>
   8#include <qtoolbar.h>
   9#include <qvbox.h>
  10#include <qsplitter.h>
  11#include <qlistview.h>
  12#include <qtextview.h>
  13#include <qlineedit.h>
  14#include <qmenubar.h>
  15#include <qmessagebox.h>
  16#include <qaction.h>
  17#include <qheader.h>
  18#include <qfiledialog.h>
  19#include <qregexp.h>
  20
  21#include <stdlib.h>
  22
  23#include "lkc.h"
  24#include "qconf.h"
  25
  26#include "qconf.moc"
  27#include "images.c"
  28
  29#ifdef _
  30# undef _
  31# define _ qgettext
  32#endif
  33
  34static QApplication *configApp;
  35
  36static inline QString qgettext(const char* str)
  37{
  38  return QString::fromLocal8Bit(gettext(str));
  39}
  40
  41static inline QString qgettext(const QString& str)
  42{
  43  return QString::fromLocal8Bit(gettext(str.latin1()));
  44}
  45
  46ConfigSettings::ConfigSettings()
  47        : showAll(false), showName(false), showRange(false), showData(false)
  48{
  49}
  50
  51#if QT_VERSION >= 300
  52/**
  53 * Reads the list column settings from the application settings.
  54 */
  55void ConfigSettings::readListSettings()
  56{
  57        showAll = readBoolEntry("/kconfig/qconf/showAll", false);
  58        showName = readBoolEntry("/kconfig/qconf/showName", false);
  59        showRange = readBoolEntry("/kconfig/qconf/showRange", false);
  60        showData = readBoolEntry("/kconfig/qconf/showData", false);
  61}
  62
  63/**
  64 * Reads a list of integer values from the application settings.
  65 */
  66QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
  67{
  68        QValueList<int> result;
  69        QStringList entryList = readListEntry(key, ok);
  70        if (ok) {
  71                QStringList::Iterator it;
  72                for (it = entryList.begin(); it != entryList.end(); ++it)
  73                        result.push_back((*it).toInt());
  74        }
  75
  76        return result;
  77}
  78
  79/**
  80 * Writes a list of integer values to the application settings.
  81 */
  82bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
  83{
  84        QStringList stringList;
  85        QValueList<int>::ConstIterator it;
  86
  87        for (it = value.begin(); it != value.end(); ++it)
  88                stringList.push_back(QString::number(*it));
  89        return writeEntry(key, stringList);
  90}
  91#endif
  92
  93
  94/*
  95 * update all the children of a menu entry
  96 *   removes/adds the entries from the parent widget as necessary
  97 *
  98 * parent: either the menu list widget or a menu entry widget
  99 * menu: entry to be updated
 100 */
 101template <class P>
 102void ConfigList::updateMenuList(P* parent, struct menu* menu)
 103{
 104        struct menu* child;
 105        ConfigItem* item;
 106        ConfigItem* last;
 107        bool visible;
 108        enum prop_type type;
 109
 110        if (!menu) {
 111                while ((item = parent->firstChild()))
 112                        delete item;
 113                return;
 114        }
 115
 116        last = parent->firstChild();
 117        if (last && !last->goParent)
 118                last = 0;
 119        for (child = menu->list; child; child = child->next) {
 120                item = last ? last->nextSibling() : parent->firstChild();
 121                type = child->prompt ? child->prompt->type : P_UNKNOWN;
 122
 123                switch (mode) {
 124                case menuMode:
 125                        if (!(child->flags & MENU_ROOT))
 126                                goto hide;
 127                        break;
 128                case symbolMode:
 129                        if (child->flags & MENU_ROOT)
 130                                goto hide;
 131                        break;
 132                default:
 133                        break;
 134                }
 135
 136                visible = menu_is_visible(child);
 137                if (showAll || visible) {
 138                        if (!item || item->menu != child)
 139                                item = new ConfigItem(parent, last, child, visible);
 140                        else
 141                                item->testUpdateMenu(visible);
 142
 143                        if (mode == fullMode || mode == menuMode || type != P_MENU)
 144                                updateMenuList(item, child);
 145                        else
 146                                updateMenuList(item, 0);
 147                        last = item;
 148                        continue;
 149                }
 150        hide:
 151                if (item && item->menu == child) {
 152                        last = parent->firstChild();
 153                        if (last == item)
 154                                last = 0;
 155                        else while (last->nextSibling() != item)
 156                                last = last->nextSibling();
 157                        delete item;
 158                }
 159        }
 160}
 161
 162#if QT_VERSION >= 300
 163/*
 164 * set the new data
 165 * TODO check the value
 166 */
 167void ConfigItem::okRename(int col)
 168{
 169        Parent::okRename(col);
 170        sym_set_string_value(menu->sym, text(dataColIdx).latin1());
 171}
 172#endif
 173
 174/*
 175 * update the displayed of a menu entry
 176 */
 177void ConfigItem::updateMenu(void)
 178{
 179        ConfigList* list;
 180        struct symbol* sym;
 181        struct property *prop;
 182        QString prompt;
 183        int type;
 184        tristate expr;
 185
 186        list = listView();
 187        if (goParent) {
 188                setPixmap(promptColIdx, list->menuBackPix);
 189                prompt = "..";
 190                goto set_prompt;
 191        }
 192
 193        sym = menu->sym;
 194        prop = menu->prompt;
 195        prompt = QString::fromLocal8Bit(menu_get_prompt(menu));
 196
 197        if (prop) switch (prop->type) {
 198        case P_MENU:
 199                if (list->mode == singleMode || list->mode == symbolMode) {
 200                        /* a menuconfig entry is displayed differently
 201                         * depending whether it's at the view root or a child.
 202                         */
 203                        if (sym && list->rootEntry == menu)
 204                                break;
 205                        setPixmap(promptColIdx, list->menuPix);
 206                } else {
 207                        if (sym)
 208                                break;
 209                        setPixmap(promptColIdx, 0);
 210                }
 211                goto set_prompt;
 212        case P_COMMENT:
 213                setPixmap(promptColIdx, 0);
 214                goto set_prompt;
 215        default:
 216                ;
 217        }
 218        if (!sym)
 219                goto set_prompt;
 220
 221        setText(nameColIdx, QString::fromLocal8Bit(sym->name));
 222
 223        type = sym_get_type(sym);
 224        switch (type) {
 225        case S_BOOLEAN:
 226        case S_TRISTATE:
 227                char ch;
 228
 229                if (!sym_is_changable(sym) && !list->showAll) {
 230                        setPixmap(promptColIdx, 0);
 231                        setText(noColIdx, QString::null);
 232                        setText(modColIdx, QString::null);
 233                        setText(yesColIdx, QString::null);
 234                        break;
 235                }
 236                expr = sym_get_tristate_value(sym);
 237                switch (expr) {
 238                case yes:
 239                        if (sym_is_choice_value(sym) && type == S_BOOLEAN)
 240                                setPixmap(promptColIdx, list->choiceYesPix);
 241                        else
 242                                setPixmap(promptColIdx, list->symbolYesPix);
 243                        setText(yesColIdx, "Y");
 244                        ch = 'Y';
 245                        break;
 246                case mod:
 247                        setPixmap(promptColIdx, list->symbolModPix);
 248                        setText(modColIdx, "M");
 249                        ch = 'M';
 250                        break;
 251                default:
 252                        if (sym_is_choice_value(sym) && type == S_BOOLEAN)
 253                                setPixmap(promptColIdx, list->choiceNoPix);
 254                        else
 255                                setPixmap(promptColIdx, list->symbolNoPix);
 256                        setText(noColIdx, "N");
 257                        ch = 'N';
 258                        break;
 259                }
 260                if (expr != no)
 261                        setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
 262                if (expr != mod)
 263                        setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
 264                if (expr != yes)
 265                        setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
 266
 267                setText(dataColIdx, QChar(ch));
 268                break;
 269        case S_INT:
 270        case S_HEX:
 271        case S_STRING:
 272                const char* data;
 273
 274                data = sym_get_string_value(sym);
 275
 276#if QT_VERSION >= 300
 277                int i = list->mapIdx(dataColIdx);
 278                if (i >= 0)
 279                        setRenameEnabled(i, TRUE);
 280#endif
 281                setText(dataColIdx, data);
 282                if (type == S_STRING)
 283                        prompt = QString("%1: %2").arg(prompt).arg(data);
 284                else
 285                        prompt = QString("(%2) %1").arg(prompt).arg(data);
 286                break;
 287        }
 288        if (!sym_has_value(sym) && visible)
 289                prompt += " (NEW)";
 290set_prompt:
 291        setText(promptColIdx, prompt);
 292}
 293
 294void ConfigItem::testUpdateMenu(bool v)
 295{
 296        ConfigItem* i;
 297
 298        visible = v;
 299        if (!menu)
 300                return;
 301
 302        sym_calc_value(menu->sym);
 303        if (menu->flags & MENU_CHANGED) {
 304                /* the menu entry changed, so update all list items */
 305                menu->flags &= ~MENU_CHANGED;
 306                for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
 307                        i->updateMenu();
 308        } else if (listView()->updateAll)
 309                updateMenu();
 310}
 311
 312void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
 313{
 314        ConfigList* list = listView();
 315
 316        if (visible) {
 317                if (isSelected() && !list->hasFocus() && list->mode == menuMode)
 318                        Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
 319                else
 320                        Parent::paintCell(p, cg, column, width, align);
 321        } else
 322                Parent::paintCell(p, list->disabledColorGroup, column, width, align);
 323}
 324
 325/*
 326 * construct a menu entry
 327 */
 328void ConfigItem::init(void)
 329{
 330        if (menu) {
 331                ConfigList* list = listView();
 332                nextItem = (ConfigItem*)menu->data;
 333                menu->data = this;
 334
 335                if (list->mode != fullMode)
 336                        setOpen(TRUE);
 337                sym_calc_value(menu->sym);
 338        }
 339        updateMenu();
 340}
 341
 342/*
 343 * destruct a menu entry
 344 */
 345ConfigItem::~ConfigItem(void)
 346{
 347        if (menu) {
 348                ConfigItem** ip = (ConfigItem**)&menu->data;
 349                for (; *ip; ip = &(*ip)->nextItem) {
 350                        if (*ip == this) {
 351                                *ip = nextItem;
 352                                break;
 353                        }
 354                }
 355        }
 356}
 357
 358void ConfigLineEdit::show(ConfigItem* i)
 359{
 360        item = i;
 361        if (sym_get_string_value(item->menu->sym))
 362                setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
 363        else
 364                setText(QString::null);
 365        Parent::show();
 366        setFocus();
 367}
 368
 369void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
 370{
 371        switch (e->key()) {
 372        case Key_Escape:
 373                break;
 374        case Key_Return:
 375        case Key_Enter:
 376                sym_set_string_value(item->menu->sym, text().latin1());
 377                parent()->updateList(item);
 378                break;
 379        default:
 380                Parent::keyPressEvent(e);
 381                return;
 382        }
 383        e->accept();
 384        parent()->list->setFocus();
 385        hide();
 386}
 387
 388ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings)
 389        : Parent(p), cview(cv),
 390          updateAll(false),
 391          symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
 392          choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
 393          menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
 394          showAll(false), showName(false), showRange(false), showData(false),
 395          rootEntry(0)
 396{
 397        int i;
 398
 399        setSorting(-1);
 400        setRootIsDecorated(TRUE);
 401        disabledColorGroup = palette().active();
 402        disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
 403        inactivedColorGroup = palette().active();
 404        inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
 405
 406        connect(this, SIGNAL(selectionChanged(void)),
 407                SLOT(updateSelection(void)));
 408
 409        if (configSettings) {
 410                showAll = configSettings->showAll;
 411                showName = configSettings->showName;
 412                showRange = configSettings->showRange;
 413                showData = configSettings->showData;
 414        }
 415
 416        for (i = 0; i < colNr; i++)
 417                colMap[i] = colRevMap[i] = -1;
 418        addColumn(promptColIdx, "Option");
 419
 420        reinit();
 421}
 422
 423void ConfigList::reinit(void)
 424{
 425        removeColumn(dataColIdx);
 426        removeColumn(yesColIdx);
 427        removeColumn(modColIdx);
 428        removeColumn(noColIdx);
 429        removeColumn(nameColIdx);
 430
 431        if (showName)
 432                addColumn(nameColIdx, "Name");
 433        if (showRange) {
 434                addColumn(noColIdx, "N");
 435                addColumn(modColIdx, "M");
 436                addColumn(yesColIdx, "Y");
 437        }
 438        if (showData)
 439                addColumn(dataColIdx, "Value");
 440
 441        updateListAll();
 442}
 443
 444void ConfigList::updateSelection(void)
 445{
 446        struct menu *menu;
 447        enum prop_type type;
 448
 449        ConfigItem* item = (ConfigItem*)selectedItem();
 450        if (!item)
 451                return;
 452
 453        cview->setHelp(item);
 454
 455        menu = item->menu;
 456        if (!menu)
 457                return;
 458        type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 459        if (mode == menuMode && type == P_MENU)
 460                emit menuSelected(menu);
 461}
 462
 463void ConfigList::updateList(ConfigItem* item)
 464{
 465        ConfigItem* last = 0;
 466
 467        if (!rootEntry)
 468                goto update;
 469
 470        if (rootEntry != &rootmenu && (mode == singleMode ||
 471            (mode == symbolMode && rootEntry->parent != &rootmenu))) {
 472                item = firstChild();
 473                if (!item)
 474                        item = new ConfigItem(this, 0, true);
 475                last = item;
 476        }
 477        if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
 478            rootEntry->sym && rootEntry->prompt) {
 479                item = last ? last->nextSibling() : firstChild();
 480                if (!item)
 481                        item = new ConfigItem(this, last, rootEntry, true);
 482                else
 483                        item->testUpdateMenu(true);
 484
 485                updateMenuList(item, rootEntry);
 486                triggerUpdate();
 487                return;
 488        }
 489update:
 490        updateMenuList(this, rootEntry);
 491        triggerUpdate();
 492}
 493
 494void ConfigList::setAllOpen(bool open)
 495{
 496        QListViewItemIterator it(this);
 497
 498        for (; it.current(); it++)
 499                it.current()->setOpen(open);
 500}
 501
 502void ConfigList::setValue(ConfigItem* item, tristate val)
 503{
 504        struct symbol* sym;
 505        int type;
 506        tristate oldval;
 507
 508        sym = item->menu ? item->menu->sym : 0;
 509        if (!sym)
 510                return;
 511
 512        type = sym_get_type(sym);
 513        switch (type) {
 514        case S_BOOLEAN:
 515        case S_TRISTATE:
 516                oldval = sym_get_tristate_value(sym);
 517
 518                if (!sym_set_tristate_value(sym, val))
 519                        return;
 520                if (oldval == no && item->menu->list)
 521                        item->setOpen(TRUE);
 522                parent()->updateList(item);
 523                break;
 524        }
 525}
 526
 527void ConfigList::changeValue(ConfigItem* item)
 528{
 529        struct symbol* sym;
 530        struct menu* menu;
 531        int type, oldexpr, newexpr;
 532
 533        menu = item->menu;
 534        if (!menu)
 535                return;
 536        sym = menu->sym;
 537        if (!sym) {
 538                if (item->menu->list)
 539                        item->setOpen(!item->isOpen());
 540                return;
 541        }
 542
 543        type = sym_get_type(sym);
 544        switch (type) {
 545        case S_BOOLEAN:
 546        case S_TRISTATE:
 547                oldexpr = sym_get_tristate_value(sym);
 548                newexpr = sym_toggle_tristate_value(sym);
 549                if (item->menu->list) {
 550                        if (oldexpr == newexpr)
 551                                item->setOpen(!item->isOpen());
 552                        else if (oldexpr == no)
 553                                item->setOpen(TRUE);
 554                }
 555                if (oldexpr != newexpr)
 556                        parent()->updateList(item);
 557                break;
 558        case S_INT:
 559        case S_HEX:
 560        case S_STRING:
 561#if QT_VERSION >= 300
 562                if (colMap[dataColIdx] >= 0)
 563                        item->startRename(colMap[dataColIdx]);
 564                else
 565#endif
 566                        parent()->lineEdit->show(item);
 567                break;
 568        }
 569}
 570
 571void ConfigList::setRootMenu(struct menu *menu)
 572{
 573        enum prop_type type;
 574
 575        if (rootEntry == menu)
 576                return;
 577        type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
 578        if (type != P_MENU)
 579                return;
 580        updateMenuList(this, 0);
 581        rootEntry = menu;
 582        updateListAll();
 583        setSelected(currentItem(), hasFocus());
 584}
 585
 586void ConfigList::setParentMenu(void)
 587{
 588        ConfigItem* item;
 589        struct menu *oldroot;
 590
 591        oldroot = rootEntry;
 592        if (rootEntry == &rootmenu)
 593                return;
 594        setRootMenu(menu_get_parent_menu(rootEntry->parent));
 595
 596        QListViewItemIterator it(this);
 597        for (; (item = (ConfigItem*)it.current()); it++) {
 598                if (item->menu == oldroot) {
 599                        setCurrentItem(item);
 600                        ensureItemVisible(item);
 601                        break;
 602                }
 603        }
 604}
 605
 606void ConfigList::keyPressEvent(QKeyEvent* ev)
 607{
 608        QListViewItem* i = currentItem();
 609        ConfigItem* item;
 610        struct menu *menu;
 611        enum prop_type type;
 612
 613        if (ev->key() == Key_Escape && mode != fullMode) {
 614                emit parentSelected();
 615                ev->accept();
 616                return;
 617        }
 618
 619        if (!i) {
 620                Parent::keyPressEvent(ev);
 621                return;
 622        }
 623        item = (ConfigItem*)i;
 624
 625        switch (ev->key()) {
 626        case Key_Return:
 627        case Key_Enter:
 628                if (item->goParent) {
 629                        emit parentSelected();
 630                        break;
 631                }
 632                menu = item->menu;
 633                if (!menu)
 634                        break;
 635                type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 636                if (type == P_MENU && rootEntry != menu &&
 637                    mode != fullMode && mode != menuMode) {
 638                        emit menuSelected(menu);
 639                        break;
 640                }
 641        case Key_Space:
 642                changeValue(item);
 643                break;
 644        case Key_N:
 645                setValue(item, no);
 646                break;
 647        case Key_M:
 648                setValue(item, mod);
 649                break;
 650        case Key_Y:
 651                setValue(item, yes);
 652                break;
 653        default:
 654                Parent::keyPressEvent(ev);
 655                return;
 656        }
 657        ev->accept();
 658}
 659
 660void ConfigList::contentsMousePressEvent(QMouseEvent* e)
 661{
 662        //QPoint p(contentsToViewport(e->pos()));
 663        //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
 664        Parent::contentsMousePressEvent(e);
 665}
 666
 667void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
 668{
 669        QPoint p(contentsToViewport(e->pos()));
 670        ConfigItem* item = (ConfigItem*)itemAt(p);
 671        struct menu *menu;
 672        enum prop_type ptype;
 673        const QPixmap* pm;
 674        int idx, x;
 675
 676        if (!item)
 677                goto skip;
 678
 679        menu = item->menu;
 680        x = header()->offset() + p.x();
 681        idx = colRevMap[header()->sectionAt(x)];
 682        switch (idx) {
 683        case promptColIdx:
 684                pm = item->pixmap(promptColIdx);
 685                if (pm) {
 686                        int off = header()->sectionPos(0) + itemMargin() +
 687                                treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
 688                        if (x >= off && x < off + pm->width()) {
 689                                if (item->goParent) {
 690                                        emit parentSelected();
 691                                        break;
 692                                } else if (!menu)
 693                                        break;
 694                                ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 695                                if (ptype == P_MENU && rootEntry != menu &&
 696                                    mode != fullMode && mode != menuMode)
 697                                        emit menuSelected(menu);
 698                                else
 699                                        changeValue(item);
 700                        }
 701                }
 702                break;
 703        case noColIdx:
 704                setValue(item, no);
 705                break;
 706        case modColIdx:
 707                setValue(item, mod);
 708                break;
 709        case yesColIdx:
 710                setValue(item, yes);
 711                break;
 712        case dataColIdx:
 713                changeValue(item);
 714                break;
 715        }
 716
 717skip:
 718        //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
 719        Parent::contentsMouseReleaseEvent(e);
 720}
 721
 722void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
 723{
 724        //QPoint p(contentsToViewport(e->pos()));
 725        //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
 726        Parent::contentsMouseMoveEvent(e);
 727}
 728
 729void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
 730{
 731        QPoint p(contentsToViewport(e->pos()));
 732        ConfigItem* item = (ConfigItem*)itemAt(p);
 733        struct menu *menu;
 734        enum prop_type ptype;
 735
 736        if (!item)
 737                goto skip;
 738        if (item->goParent) {
 739                emit parentSelected();
 740                goto skip;
 741        }
 742        menu = item->menu;
 743        if (!menu)
 744                goto skip;
 745        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 746        if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
 747                emit menuSelected(menu);
 748        else if (menu->sym)
 749                changeValue(item);
 750
 751skip:
 752        //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
 753        Parent::contentsMouseDoubleClickEvent(e);
 754}
 755
 756void ConfigList::focusInEvent(QFocusEvent *e)
 757{
 758        Parent::focusInEvent(e);
 759
 760        QListViewItem* item = currentItem();
 761        if (!item)
 762                return;
 763
 764        setSelected(item, TRUE);
 765        emit gotFocus();
 766}
 767
 768ConfigView* ConfigView::viewList;
 769
 770ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview,
 771                       ConfigSettings *configSettings)
 772        : Parent(parent)
 773{
 774        list = new ConfigList(this, cview, configSettings);
 775        lineEdit = new ConfigLineEdit(this);
 776        lineEdit->hide();
 777
 778        this->nextView = viewList;
 779        viewList = this;
 780}
 781
 782ConfigView::~ConfigView(void)
 783{
 784        ConfigView** vp;
 785
 786        for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
 787                if (*vp == this) {
 788                        *vp = nextView;
 789                        break;
 790                }
 791        }
 792}
 793
 794void ConfigView::updateList(ConfigItem* item)
 795{
 796        ConfigView* v;
 797
 798        for (v = viewList; v; v = v->nextView)
 799                v->list->updateList(item);
 800}
 801
 802void ConfigView::updateListAll(void)
 803{
 804        ConfigView* v;
 805
 806        for (v = viewList; v; v = v->nextView)
 807                v->list->updateListAll();
 808}
 809
 810/*
 811 * Construct the complete config widget
 812 */
 813ConfigMainWindow::ConfigMainWindow(void)
 814{
 815        QMenuBar* menu;
 816        bool ok;
 817        int x, y, width, height;
 818
 819        QWidget *d = configApp->desktop();
 820
 821        ConfigSettings* configSettings = new ConfigSettings();
 822#if QT_VERSION >= 300
 823        width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
 824        height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
 825        resize(width, height);
 826        x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok);
 827        if (ok)
 828                y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
 829        if (ok)
 830                move(x, y);
 831        showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false);
 832
 833        // read list settings into configSettings, will be used later for ConfigList setup
 834        configSettings->readListSettings();
 835#else
 836        width = d->width() - 64;
 837        height = d->height() - 64;
 838        resize(width, height);
 839        showDebug = false;
 840#endif
 841
 842        split1 = new QSplitter(this);
 843        split1->setOrientation(QSplitter::Horizontal);
 844        setCentralWidget(split1);
 845
 846        menuView = new ConfigView(split1, this, configSettings);
 847        menuList = menuView->list;
 848
 849        split2 = new QSplitter(split1);
 850        split2->setOrientation(QSplitter::Vertical);
 851
 852        // create config tree
 853        configView = new ConfigView(split2, this, configSettings);
 854        configList = configView->list;
 855
 856        helpText = new QTextView(split2);
 857        helpText->setTextFormat(Qt::RichText);
 858
 859        setTabOrder(configList, helpText);
 860        configList->setFocus();
 861
 862        menu = menuBar();
 863        toolBar = new QToolBar("Tools", this);
 864
 865        backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
 866          connect(backAction, SIGNAL(activated()), SLOT(goBack()));
 867          backAction->setEnabled(FALSE);
 868        QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
 869          connect(quitAction, SIGNAL(activated()), SLOT(close()));
 870        QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
 871          connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
 872        QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
 873          connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
 874        QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
 875          connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
 876        QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
 877          connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
 878        QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
 879          connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
 880        QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
 881          connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
 882
 883        QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
 884          showNameAction->setToggleAction(TRUE);
 885          showNameAction->setOn(configList->showName);
 886          connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool)));
 887        QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
 888          showRangeAction->setToggleAction(TRUE);
 889          showRangeAction->setOn(configList->showRange);
 890          connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool)));
 891        QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
 892          showDataAction->setToggleAction(TRUE);
 893          showDataAction->setOn(configList->showData);
 894          connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool)));
 895        QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
 896          showAllAction->setToggleAction(TRUE);
 897          showAllAction->setOn(configList->showAll);
 898          connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool)));
 899        QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
 900          showDebugAction->setToggleAction(TRUE);
 901          showDebugAction->setOn(showDebug);
 902          connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
 903
 904        QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
 905          connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
 906        QAction *showAboutAction = new QAction(NULL, "About", 0, this);
 907          connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
 908
 909        // init tool bar
 910        backAction->addTo(toolBar);
 911        toolBar->addSeparator();
 912        loadAction->addTo(toolBar);
 913        saveAction->addTo(toolBar);
 914        toolBar->addSeparator();
 915        singleViewAction->addTo(toolBar);
 916        splitViewAction->addTo(toolBar);
 917        fullViewAction->addTo(toolBar);
 918
 919        // create config menu
 920        QPopupMenu* config = new QPopupMenu(this);
 921        menu->insertItem("&File", config);
 922        loadAction->addTo(config);
 923        saveAction->addTo(config);
 924        saveAsAction->addTo(config);
 925        config->insertSeparator();
 926        quitAction->addTo(config);
 927
 928        // create options menu
 929        QPopupMenu* optionMenu = new QPopupMenu(this);
 930        menu->insertItem("&Option", optionMenu);
 931        showNameAction->addTo(optionMenu);
 932        showRangeAction->addTo(optionMenu);
 933        showDataAction->addTo(optionMenu);
 934        optionMenu->insertSeparator();
 935        showAllAction->addTo(optionMenu);
 936        showDebugAction->addTo(optionMenu);
 937
 938        // create help menu
 939        QPopupMenu* helpMenu = new QPopupMenu(this);
 940        menu->insertSeparator();
 941        menu->insertItem("&Help", helpMenu);
 942        showIntroAction->addTo(helpMenu);
 943        showAboutAction->addTo(helpMenu);
 944
 945        connect(configList, SIGNAL(menuSelected(struct menu *)),
 946                SLOT(changeMenu(struct menu *)));
 947        connect(configList, SIGNAL(parentSelected()),
 948                SLOT(goBack()));
 949        connect(menuList, SIGNAL(menuSelected(struct menu *)),
 950                SLOT(changeMenu(struct menu *)));
 951
 952        connect(configList, SIGNAL(gotFocus(void)),
 953                SLOT(listFocusChanged(void)));
 954        connect(menuList, SIGNAL(gotFocus(void)),
 955                SLOT(listFocusChanged(void)));
 956
 957#if QT_VERSION >= 300
 958        QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol");
 959        if (listMode == "single")
 960                showSingleView();
 961        else if (listMode == "full")
 962                showFullView();
 963        else /*if (listMode == "split")*/
 964                showSplitView();
 965
 966        // UI setup done, restore splitter positions
 967        QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok);
 968        if (ok)
 969                split1->setSizes(sizes);
 970
 971        sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok);
 972        if (ok)
 973                split2->setSizes(sizes);
 974#else
 975        showSplitView();
 976#endif
 977        delete configSettings;
 978}
 979
 980static QString print_filter(const QString &str)
 981{
 982        QRegExp re("[<>&\"\\n]");
 983        QString res = str;
 984        for (int i = 0; (i = res.find(re, i)) >= 0;) {
 985                switch (res[i].latin1()) {
 986                case '<':
 987                        res.replace(i, 1, "&lt;");
 988                        i += 4;
 989                        break;
 990                case '>':
 991                        res.replace(i, 1, "&gt;");
 992                        i += 4;
 993                        break;
 994                case '&':
 995                        res.replace(i, 1, "&amp;");
 996                        i += 5;
 997                        break;
 998                case '"':
 999                        res.replace(i, 1, "&quot;");
1000                        i += 6;
1001                        break;
1002                case '\n':
1003                        res.replace(i, 1, "<br>");
1004                        i += 4;
1005                        break;
1006                }
1007        }
1008        return res;
1009}
1010
1011static void expr_print_help(void *data, const char *str)
1012{
1013        reinterpret_cast<QString*>(data)->append(print_filter(str));
1014}
1015
1016/*
1017 * display a new help entry as soon as a new menu entry is selected
1018 */
1019void ConfigMainWindow::setHelp(QListViewItem* item)
1020{
1021        struct symbol* sym;
1022        struct menu* menu = 0;
1023
1024        configList->parent()->lineEdit->hide();
1025        if (item)
1026                menu = ((ConfigItem*)item)->menu;
1027        if (!menu) {
1028                helpText->setText(QString::null);
1029                return;
1030        }
1031
1032        QString head, debug, help;
1033        menu = ((ConfigItem*)item)->menu;
1034        sym = menu->sym;
1035        if (sym) {
1036                if (menu->prompt) {
1037                        head += "<big><b>";
1038                        head += print_filter(_(menu->prompt->text));
1039                        head += "</b></big>";
1040                        if (sym->name) {
1041                                head += " (";
1042                                head += print_filter(_(sym->name));
1043                                head += ")";
1044                        }
1045                } else if (sym->name) {
1046                        head += "<big><b>";
1047                        head += print_filter(_(sym->name));
1048                        head += "</b></big>";
1049                }
1050                head += "<br><br>";
1051
1052                if (showDebug) {
1053                        debug += "type: ";
1054                        debug += print_filter(sym_type_name(sym->type));
1055                        if (sym_is_choice(sym))
1056                                debug += " (choice)";
1057                        debug += "<br>";
1058                        if (sym->rev_dep.expr) {
1059                                debug += "reverse dep: ";
1060                                expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1061                                debug += "<br>";
1062                        }
1063                        for (struct property *prop = sym->prop; prop; prop = prop->next) {
1064                                switch (prop->type) {
1065                                case P_PROMPT:
1066                                case P_MENU:
1067                                        debug += "prompt: ";
1068                                        debug += print_filter(_(prop->text));
1069                                        debug += "<br>";
1070                                        break;
1071                                case P_DEFAULT:
1072                                        debug += "default: ";
1073                                        expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1074                                        debug += "<br>";
1075                                        break;
1076                                case P_CHOICE:
1077                                        if (sym_is_choice(sym)) {
1078                                                debug += "choice: ";
1079                                                expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1080                                                debug += "<br>";
1081                                        }
1082                                        break;
1083                                case P_SELECT:
1084                                        debug += "select: ";
1085                                        expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1086                                        debug += "<br>";
1087                                        break;
1088                                case P_RANGE:
1089                                        debug += "range: ";
1090                                        expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1091                                        debug += "<br>";
1092                                        break;
1093                                default:
1094                                        debug += "unknown property: ";
1095                                        debug += prop_get_type_name(prop->type);
1096                                        debug += "<br>";
1097                                }
1098                                if (prop->visible.expr) {
1099                                        debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1100                                        expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1101                                        debug += "<br>";
1102                                }
1103                        }
1104                        debug += "<br>";
1105                }
1106
1107                help = print_filter(_(sym->help));
1108        } else if (menu->prompt) {
1109                head += "<big><b>";
1110                head += print_filter(_(menu->prompt->text));
1111                head += "</b></big><br><br>";
1112                if (showDebug) {
1113                        if (menu->prompt->visible.expr) {
1114                                debug += "&nbsp;&nbsp;dep: ";
1115                                expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1116                                debug += "<br><br>";
1117                        }
1118                }
1119        }
1120        if (showDebug)
1121                debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
1122        helpText->setText(head + debug + help);
1123}
1124
1125void ConfigMainWindow::loadConfig(void)
1126{
1127        QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1128        if (s.isNull())
1129                return;
1130        if (conf_read(QFile::encodeName(s)))
1131                QMessageBox::information(this, "qconf", "Unable to load configuration!");
1132        ConfigView::updateListAll();
1133}
1134
1135void ConfigMainWindow::saveConfig(void)
1136{
1137        if (conf_write(NULL))
1138                QMessageBox::information(this, "qconf", "Unable to save configuration!");
1139}
1140
1141void ConfigMainWindow::saveConfigAs(void)
1142{
1143        QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1144        if (s.isNull())
1145                return;
1146        if (conf_write(QFile::encodeName(s)))
1147                QMessageBox::information(this, "qconf", "Unable to save configuration!");
1148}
1149
1150void ConfigMainWindow::changeMenu(struct menu *menu)
1151{
1152        configList->setRootMenu(menu);
1153        backAction->setEnabled(TRUE);
1154}
1155
1156void ConfigMainWindow::listFocusChanged(void)
1157{
1158        if (menuList->hasFocus()) {
1159                if (menuList->mode == menuMode)
1160                        configList->clearSelection();
1161                setHelp(menuList->selectedItem());
1162        } else if (configList->hasFocus()) {
1163                setHelp(configList->selectedItem());
1164        }
1165}
1166
1167void ConfigMainWindow::goBack(void)
1168{
1169        ConfigItem* item;
1170
1171        configList->setParentMenu();
1172        if (configList->rootEntry == &rootmenu)
1173                backAction->setEnabled(FALSE);
1174        item = (ConfigItem*)menuList->selectedItem();
1175        while (item) {
1176                if (item->menu == configList->rootEntry) {
1177                        menuList->setSelected(item, TRUE);
1178                        break;
1179                }
1180                item = (ConfigItem*)item->parent();
1181        }
1182}
1183
1184void ConfigMainWindow::showSingleView(void)
1185{
1186        menuView->hide();
1187        menuList->setRootMenu(0);
1188        configList->mode = singleMode;
1189        if (configList->rootEntry == &rootmenu)
1190                configList->updateListAll();
1191        else
1192                configList->setRootMenu(&rootmenu);
1193        configList->setAllOpen(TRUE);
1194        configList->setFocus();
1195}
1196
1197void ConfigMainWindow::showSplitView(void)
1198{
1199        configList->mode = symbolMode;
1200        if (configList->rootEntry == &rootmenu)
1201                configList->updateListAll();
1202        else
1203                configList->setRootMenu(&rootmenu);
1204        configList->setAllOpen(TRUE);
1205        configApp->processEvents();
1206        menuList->mode = menuMode;
1207        menuList->setRootMenu(&rootmenu);
1208        menuList->setAllOpen(TRUE);
1209        menuView->show();
1210        menuList->setFocus();
1211}
1212
1213void ConfigMainWindow::showFullView(void)
1214{
1215        menuView->hide();
1216        menuList->setRootMenu(0);
1217        configList->mode = fullMode;
1218        if (configList->rootEntry == &rootmenu)
1219                configList->updateListAll();
1220        else
1221                configList->setRootMenu(&rootmenu);
1222        configList->setAllOpen(FALSE);
1223        configList->setFocus();
1224}
1225
1226void ConfigMainWindow::setShowAll(bool b)
1227{
1228        if (configList->showAll == b)
1229                return;
1230        configList->showAll = b;
1231        configList->updateListAll();
1232        menuList->showAll = b;
1233        menuList->updateListAll();
1234}
1235
1236void ConfigMainWindow::setShowDebug(bool b)
1237{
1238        if (showDebug == b)
1239                return;
1240        showDebug = b;
1241}
1242
1243void ConfigMainWindow::setShowName(bool b)
1244{
1245        if (configList->showName == b)
1246                return;
1247        configList->showName = b;
1248        configList->reinit();
1249        menuList->showName = b;
1250        menuList->reinit();
1251}
1252
1253void ConfigMainWindow::setShowRange(bool b)
1254{
1255        if (configList->showRange == b)
1256                return;
1257        configList->showRange = b;
1258        configList->reinit();
1259        menuList->showRange = b;
1260        menuList->reinit();
1261}
1262
1263void ConfigMainWindow::setShowData(bool b)
1264{
1265        if (configList->showData == b)
1266                return;
1267        configList->showData = b;
1268        configList->reinit();
1269        menuList->showData = b;
1270        menuList->reinit();
1271}
1272
1273/*
1274 * ask for saving configuration before quitting
1275 * TODO ask only when something changed
1276 */
1277void ConfigMainWindow::closeEvent(QCloseEvent* e)
1278{
1279        if (!sym_change_count) {
1280                e->accept();
1281                return;
1282        }
1283        QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1284                        QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1285        mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1286        mb.setButtonText(QMessageBox::No, "&Discard Changes");
1287        mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1288        switch (mb.exec()) {
1289        case QMessageBox::Yes:
1290                conf_write(NULL);
1291        case QMessageBox::No:
1292                e->accept();
1293                break;
1294        case QMessageBox::Cancel:
1295                e->ignore();
1296                break;
1297        }
1298}
1299
1300void ConfigMainWindow::showIntro(void)
1301{
1302        static char str[] = "Welcome to the qconf graphical configuration tool.\n\n"
1303                "For each option, a blank box indicates the feature is disabled, a check\n"
1304                "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1305                "as a module.  Clicking on the box will cycle through the three states.\n\n"
1306                "If you do not see an option (e.g., a device driver) that you believe\n"
1307                "should be present, try turning on Show All Options under the Options menu.\n"
1308                "Although there is no cross reference yet to help you figure out what other\n"
1309                "options must be enabled to support the option you are interested in, you can\n"
1310                "still view the help of a grayed-out option.\n\n"
1311                "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1312                "which you can then match by examining other options.\n\n";
1313
1314        QMessageBox::information(this, "qconf", str);
1315}
1316
1317void ConfigMainWindow::showAbout(void)
1318{
1319        static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n";
1320
1321        QMessageBox::information(this, "qconf", str);
1322}
1323
1324void ConfigMainWindow::saveSettings(void)
1325{
1326#if QT_VERSION >= 300
1327        ConfigSettings *configSettings = new ConfigSettings;
1328        configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
1329        configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
1330        configSettings->writeEntry("/kconfig/qconf/window width", size().width());
1331        configSettings->writeEntry("/kconfig/qconf/window height", size().height());
1332        configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
1333        configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
1334        configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
1335        configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
1336        configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
1337
1338        QString entry;
1339        switch(configList->mode) {
1340        case singleMode :
1341                entry = "single";
1342                break;
1343
1344        case symbolMode :
1345                entry = "split";
1346                break;
1347
1348        case fullMode :
1349                entry = "full";
1350                break;
1351        }
1352        configSettings->writeEntry("/kconfig/qconf/listMode", entry);
1353
1354        configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
1355        configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
1356
1357        delete configSettings;
1358#endif
1359}
1360
1361void fixup_rootmenu(struct menu *menu)
1362{
1363        struct menu *child;
1364        static int menu_cnt = 0;
1365
1366        menu->flags |= MENU_ROOT;
1367        for (child = menu->list; child; child = child->next) {
1368                if (child->prompt && child->prompt->type == P_MENU) {
1369                        menu_cnt++;
1370                        fixup_rootmenu(child);
1371                        menu_cnt--;
1372                } else if (!menu_cnt)
1373                        fixup_rootmenu(child);
1374        }
1375}
1376
1377static const char *progname;
1378
1379static void usage(void)
1380{
1381        printf("%s <config>\n", progname);
1382        exit(0);
1383}
1384
1385int main(int ac, char** av)
1386{
1387        ConfigMainWindow* v;
1388        const char *name;
1389
1390        bindtextdomain(PACKAGE, LOCALEDIR);
1391        textdomain(PACKAGE);
1392
1393#ifndef LKC_DIRECT_LINK
1394        kconfig_load();
1395#endif
1396
1397        progname = av[0];
1398        configApp = new QApplication(ac, av);
1399        if (ac > 1 && av[1][0] == '-') {
1400                switch (av[1][1]) {
1401                case 'h':
1402                case '?':
1403                        usage();
1404                }
1405                name = av[2];
1406        } else
1407                name = av[1];
1408        if (!name)
1409                usage();
1410
1411        conf_parse(name);
1412        fixup_rootmenu(&rootmenu);
1413        conf_read(NULL);
1414        //zconfdump(stdout);
1415
1416        v = new ConfigMainWindow();
1417
1418        //zconfdump(stdout);
1419        v->show();
1420        configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1421        configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1422        configApp->exec();
1423
1424        return 0;
1425}
1426