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