[TCP]: continued: reno sacked_out count fix
[linux-2.6] / scripts / kconfig / qconf.cc
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
34 static QApplication *configApp;
35
36 static inline QString qgettext(const char* str)
37 {
38   return QString::fromLocal8Bit(gettext(str));
39 }
40
41 static inline QString qgettext(const QString& str)
42 {
43   return QString::fromLocal8Bit(gettext(str.latin1()));
44 }
45
46 ConfigSettings::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  */
55 void 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  */
66 QValueList<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  */
82 bool 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  */
101 template <class P>
102 void 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  */
167 void 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  */
177 void 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)";
290 set_prompt:
291         setText(promptColIdx, prompt);
292 }
293
294 void 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
312 void 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  */
328 void 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  */
345 ConfigItem::~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
358 void 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
369 void 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
388 ConfigList::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
423 void 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
444 void 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
463 void 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         }
489 update:
490         updateMenuList(this, rootEntry);
491         triggerUpdate();
492 }
493
494 void ConfigList::setAllOpen(bool open)
495 {
496         QListViewItemIterator it(this);
497
498         for (; it.current(); it++)
499                 it.current()->setOpen(open);
500 }
501
502 void 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
527 void 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
571 void 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
586 void 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
606 void 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
660 void 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
667 void 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
717 skip:
718         //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
719         Parent::contentsMouseReleaseEvent(e);
720 }
721
722 void 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
729 void 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
751 skip:
752         //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
753         Parent::contentsMouseDoubleClickEvent(e);
754 }
755
756 void 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
768 ConfigView* ConfigView::viewList;
769
770 ConfigView::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
782 ConfigView::~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
794 void ConfigView::updateList(ConfigItem* item)
795 {
796         ConfigView* v;
797
798         for (v = viewList; v; v = v->nextView)
799                 v->list->updateList(item);
800 }
801
802 void 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  */
813 ConfigMainWindow::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
980 static 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
1011 static 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  */
1019 void 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
1125 void 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
1135 void ConfigMainWindow::saveConfig(void)
1136 {
1137         if (conf_write(NULL))
1138                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1139 }
1140
1141 void 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
1150 void ConfigMainWindow::changeMenu(struct menu *menu)
1151 {
1152         configList->setRootMenu(menu);
1153         backAction->setEnabled(TRUE);
1154 }
1155
1156 void 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
1167 void 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
1184 void 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
1197 void 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
1213 void 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
1226 void 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
1236 void ConfigMainWindow::setShowDebug(bool b)
1237 {
1238         if (showDebug == b)
1239                 return;
1240         showDebug = b;
1241 }
1242
1243 void 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
1253 void 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
1263 void 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  */
1277 void 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
1300 void ConfigMainWindow::showIntro(void)
1301 {
1302         static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\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
1317 void ConfigMainWindow::showAbout(void)
1318 {
1319         static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1320                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1321
1322         QMessageBox::information(this, "qconf", str);
1323 }
1324
1325 void ConfigMainWindow::saveSettings(void)
1326 {
1327 #if QT_VERSION >= 300
1328         ConfigSettings *configSettings = new ConfigSettings;
1329         configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
1330         configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
1331         configSettings->writeEntry("/kconfig/qconf/window width", size().width());
1332         configSettings->writeEntry("/kconfig/qconf/window height", size().height());
1333         configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
1334         configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
1335         configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
1336         configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
1337         configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
1338
1339         QString entry;
1340         switch(configList->mode) {
1341         case singleMode :
1342                 entry = "single";
1343                 break;
1344
1345         case symbolMode :
1346                 entry = "split";
1347                 break;
1348
1349         case fullMode :
1350                 entry = "full";
1351                 break;
1352         }
1353         configSettings->writeEntry("/kconfig/qconf/listMode", entry);
1354
1355         configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
1356         configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
1357
1358         delete configSettings;
1359 #endif
1360 }
1361
1362 void fixup_rootmenu(struct menu *menu)
1363 {
1364         struct menu *child;
1365         static int menu_cnt = 0;
1366
1367         menu->flags |= MENU_ROOT;
1368         for (child = menu->list; child; child = child->next) {
1369                 if (child->prompt && child->prompt->type == P_MENU) {
1370                         menu_cnt++;
1371                         fixup_rootmenu(child);
1372                         menu_cnt--;
1373                 } else if (!menu_cnt)
1374                         fixup_rootmenu(child);
1375         }
1376 }
1377
1378 static const char *progname;
1379
1380 static void usage(void)
1381 {
1382         printf("%s <config>\n", progname);
1383         exit(0);
1384 }
1385
1386 int main(int ac, char** av)
1387 {
1388         ConfigMainWindow* v;
1389         const char *name;
1390
1391         bindtextdomain(PACKAGE, LOCALEDIR);
1392         textdomain(PACKAGE);
1393
1394 #ifndef LKC_DIRECT_LINK
1395         kconfig_load();
1396 #endif
1397
1398         progname = av[0];
1399         configApp = new QApplication(ac, av);
1400         if (ac > 1 && av[1][0] == '-') {
1401                 switch (av[1][1]) {
1402                 case 'h':
1403                 case '?':
1404                         usage();
1405                 }
1406                 name = av[2];
1407         } else
1408                 name = av[1];
1409         if (!name)
1410                 usage();
1411
1412         conf_parse(name);
1413         fixup_rootmenu(&rootmenu);
1414         conf_read(NULL);
1415         //zconfdump(stdout);
1416
1417         v = new ConfigMainWindow();
1418
1419         //zconfdump(stdout);
1420         v->show();
1421         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1422         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1423         configApp->exec();
1424
1425         return 0;
1426 }