001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2002-2005 Julian Hyde
008// Copyright (C) 2005-2012 Pentaho and others
009// Copyright (C) 2006-2007 CINCOM SYSTEMS, INC.
010// All Rights Reserved.
011*/
012package mondrian.gui;
013
014import mondrian.gui.MondrianGuiDef.Hierarchy;
015import mondrian.olap.Id;
016import mondrian.olap.MondrianProperties;
017import mondrian.olap.Util;
018
019import org.eigenbase.xom.NodeDef;
020
021import java.awt.*;
022import java.awt.event.*;
023import java.io.*;
024import java.util.*;
025import java.util.List;
026import javax.swing.*;
027import javax.swing.border.EmptyBorder;
028import javax.swing.event.CellEditorListener;
029import javax.swing.event.ChangeEvent;
030import javax.swing.text.JTextComponent;
031
032/**
033 * @author sean
034 */
035public class SchemaPropertyCellEditor
036    implements javax.swing.table.TableCellEditor
037{
038    Workbench workbench;
039
040    final List<CellEditorListener> listeners =
041        new ArrayList<CellEditorListener>();
042
043    JTextField stringEditor;
044    JTextArea cdataTextArea;
045    JScrollPane jScrollPaneCDATA;
046    // JEditorPane jEditorPaneCDATA;
047    JCheckBox booleanEditor;
048    JTextField integerEditor;
049    JTable tableEditor;
050    Component activeEditor;
051    JComboBox listEditor;
052    //JComboBox relationList;  // Join, Table
053    JTable relationTable;
054    JPanel relationRenderer;
055
056    JdbcMetaData jdbcMetaData;
057    ComboBoxModel allOptions, selOptions;
058    String listEditorValue;
059    MouseListener ml;
060    ItemListener il;
061    ActionListener al;
062
063    String noSelect = "-- No Selection --";
064    FocusAdapter editorFocus;
065
066    Object originalValue;
067
068    public SchemaPropertyCellEditor(
069        Workbench workbench)
070    {
071        this(workbench, null);
072    }
073
074    /**
075     * Creates a new instance of SchemaPropertyCellEditor
076     */
077    public SchemaPropertyCellEditor(
078        Workbench workbench,
079        JdbcMetaData jdbcMetaData)
080    {
081        this.workbench = workbench;
082        this.jdbcMetaData = jdbcMetaData;
083
084        noSelect = getResourceConverter().getString(
085            "schemaPropertyCellEditor.noSelection", noSelect);
086
087        stringEditor = new JTextField();
088        stringEditor.setFont(Font.decode("Dialog"));
089        stringEditor.setBorder(null);
090
091        // cdata multi-line
092        cdataTextArea = new JTextArea();
093        cdataTextArea.setLineWrap(true);
094        cdataTextArea.setWrapStyleWord(true);
095        cdataTextArea.setLayout(new java.awt.BorderLayout());
096        cdataTextArea.setEditable(true);
097        cdataTextArea.setPreferredSize(new java.awt.Dimension(100, 300));
098        cdataTextArea.setMinimumSize(new java.awt.Dimension(100, 100));
099
100        jScrollPaneCDATA = new JScrollPane(cdataTextArea);
101        jScrollPaneCDATA.setMaximumSize(cdataTextArea.getPreferredSize());
102
103        booleanEditor = new JCheckBox();
104        booleanEditor.setBackground(Color.white);
105
106        integerEditor = new JTextField();
107        integerEditor.setBorder(null);
108        integerEditor.setHorizontalAlignment(JTextField.RIGHT);
109        integerEditor.setFont(Font.decode("Courier"));
110
111        tableEditor = new JTable();
112
113        listEditor = new JComboBox();
114        listEditor.setEditable(true);
115        listEditor.setMaximumSize(stringEditor.getMaximumSize());
116        listEditor.setFont(Font.decode("Dialog"));
117        listEditor.setBackground(Color.white);
118        listEditor.setBorder(
119            new EmptyBorder(
120                0, 0, 0, 0)); //super.noFocusBorder);
121
122        al = new ActionListener() {
123            boolean all = true;
124
125            public void actionPerformed(ActionEvent e) {
126                if (e.getActionCommand().equals("comboBoxChanged")
127                    && listEditor.getSelectedIndex() == 0)
128                {   // 0 index refers to less or more options
129                    if (all) {
130                        listEditor.setModel(allOptions);
131                    } else {
132                        listEditor.setModel(selOptions);
133                    }
134                    listEditor.setSelectedIndex(-1);
135                    all = !all;
136                }
137                // Must invoke later on the GUI thread since trying
138                // now will fail. The component is already marked
139                // as 'dirty'.
140                SwingUtilities.invokeLater(
141                    new Runnable() {
142                        public void run() {
143                            if (listEditor.isDisplayable()) {
144                                listEditor.setPopupVisible(true);
145                            }
146                        }
147                    });
148            }
149        };
150
151        JTextComponent editor =
152            (JTextComponent) listEditor.getEditor().getEditorComponent();
153
154        editor.addMouseListener(
155            new MouseAdapter() {
156                public void mousePressed(MouseEvent e) {
157                    if (listEditor.isDisplayable()) {
158                        listEditor.setPopupVisible(true);
159                    }
160                }
161            });
162
163        editor.addKeyListener(
164            new KeyAdapter() {
165                public void keyPressed(KeyEvent e) {
166                    if (listEditor.isDisplayable()) {
167                        listEditor.setPopupVisible(true);
168                    }
169                }
170
171                public void keyReleased(KeyEvent e) {
172                    // listEditor.setSelectedItem(
173                    //   ((JTextComponent) e.getSource()).getText());
174                    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
175                        listEditor.setSelectedItem(listEditorValue);
176                        listEditor.getEditor().setItem(listEditorValue);
177                    }
178                }
179            });
180
181        // Not used
182
183//        relationRenderer = new JPanel();
184//
185//        relationList = new JComboBox(
186//            new String[] {
187//                getResourceConverter().getString(
188//                    "schemaPropertyCellEditor.join","Join"),
189//                 getResourceConverter().getString(
190//                     "schemaPropertyCellEditor.table","Table")});
191//        relationList.setMaximumSize(stringEditor.getMaximumSize());
192//        relationTable = new JTable();
193//        relationRenderer.add(relationList);
194//        relationRenderer.add(relationTable);
195    }
196
197
198    public MondrianGuiDef.RelationOrJoin getRelation(
199        final JTable table,
200        final int row,
201        final int column)
202    {
203        PropertyTableModel tableModel = (PropertyTableModel) table.getModel();
204        Object value = tableModel.getValue();
205        Class<?> targetClassz = tableModel.target.getClass();
206        Object parent = this.getParentObject();
207
208        MondrianGuiDef.RelationOrJoin relation = null;
209
210        if (targetClassz == MondrianGuiDef.Table.class) {
211            relation = (MondrianGuiDef.Table) value;
212        } else if (targetClassz == MondrianGuiDef.View.class) {
213            relation = (MondrianGuiDef.View) value;
214        } else if (targetClassz == MondrianGuiDef.Join.class) {
215            relation = (MondrianGuiDef.Join) value;
216        } else if (targetClassz == MondrianGuiDef.Hierarchy.class) {
217            MondrianGuiDef.Hierarchy hProps = (MondrianGuiDef.Hierarchy) value;
218            relation = hProps.relation;
219        } else if (targetClassz == MondrianGuiDef.Level.class) {
220            MondrianGuiDef.Hierarchy hProps = (MondrianGuiDef.Hierarchy) parent;
221            relation = hProps.relation;
222        } else if (targetClassz == MondrianGuiDef.Cube.class) {
223            MondrianGuiDef.Cube hProps = (MondrianGuiDef.Cube) value;
224            relation = hProps.fact;
225        }
226
227        return relation;
228    }
229
230    public Component getTableCellEditorComponent(
231        final JTable table,
232        Object value,
233        boolean isSelected,
234        final int row,
235        final int column)
236    {
237        PropertyTableModel tableModel = (PropertyTableModel) table.getModel();
238        Class<?> parentClassz = null;
239        if (tableModel.getParentTarget() != null) {
240            parentClassz = tableModel.getParentTarget().getClass();
241        }
242        Class<?> targetClassz = tableModel.target.getClass();
243        String propertyName = tableModel.getRowName(row);
244        String selectedFactTable = tableModel.getFactTable();
245        String selectedFactTableSchema = tableModel.getFactTableSchema();
246        listEditorValue = null;  // reset value of combo-box
247        Object parent = this.getParentObject();
248
249        MondrianGuiDef.RelationOrJoin currentRelation =
250            getRelation(table, row, column);
251
252        boolean nonTableRelation =
253            currentRelation != null
254            && !(currentRelation instanceof MondrianGuiDef.Table
255                 || currentRelation instanceof MondrianGuiDef.Join);
256
257        if (targetClassz == MondrianGuiDef.UserDefinedFunction.class
258            && propertyName.equals("className"))
259        {
260            List<String> udfs = getUdfs();
261            ComboBoxModel cAlludfs =
262                new DefaultComboBoxModel(new Vector<String>(udfs));
263
264            listEditor.setEditable(true);
265            listEditor.setToolTipText(null);
266            listEditor.removeActionListener(al);
267
268            listEditor.setModel(cAlludfs);
269            listEditor.setSelectedItem((String) value);
270            listEditorValue = (String) value;
271            activeEditor = listEditor;
272        } else if (targetClassz == MondrianGuiDef.Measure.class
273                   && propertyName.equals("formatString"))
274        {
275            List<String> formatStrs = getFormatStrings();
276            ComboBoxModel cAllformatStrs =
277                new DefaultComboBoxModel(new Vector<String>(formatStrs));
278
279            listEditor.setEditable(true);
280            listEditor.setToolTipText(null);
281            listEditor.removeActionListener(al);
282
283            listEditor.setModel(cAllformatStrs);
284            listEditor.setSelectedItem((String) value);
285            listEditorValue = (String) value;
286            activeEditor = listEditor;
287        } else if (targetClassz == MondrianGuiDef.Measure.class
288                   && propertyName.equals("aggregator"))
289        {
290            listEditor.setEditable(false);
291            listEditor.setToolTipText(null);
292            listEditor.removeActionListener(al);
293            listEditor.setModel(
294                new DefaultComboBoxModel(
295                    MondrianGuiDef.Measure._aggregator_values));
296            listEditor.setSelectedItem((String) value);
297            activeEditor = listEditor;
298
299        } else if (targetClassz == MondrianGuiDef.Measure.class
300                   && propertyName.equals("datatype"))
301        {
302            listEditor.setEditable(false);
303            listEditor.setToolTipText(null);
304            listEditor.removeActionListener(al);
305            listEditor.setModel(
306                new DefaultComboBoxModel(
307                    MondrianGuiDef.Measure._datatype_values));
308            listEditor.setSelectedItem((String) value);
309            activeEditor = listEditor;
310
311        } else if (targetClassz == MondrianGuiDef.Parameter.class
312                   && propertyName.equals("parameter"))
313        {
314            listEditor.setEditable(false);
315            listEditor.setToolTipText(null);
316            listEditor.removeActionListener(al);
317            listEditor.setModel(
318                new DefaultComboBoxModel(
319                    MondrianGuiDef.Parameter._type_values));
320            listEditor.setSelectedItem((String) value);
321            activeEditor = listEditor;
322
323        } else if (targetClassz == MondrianGuiDef.SQL.class
324                   && propertyName.equals("dialect"))
325        {
326            listEditor.setEditable(false);
327            listEditor.setToolTipText(null);
328            listEditor.removeActionListener(al);
329            listEditor.setModel(
330                new DefaultComboBoxModel(MondrianGuiDef.SQL._dialect_values));
331            listEditor.setSelectedItem((String) value);
332            activeEditor = listEditor;
333
334        } else if (targetClassz == MondrianGuiDef.Level.class
335                   && propertyName.equals("hideMemberIf"))
336        {
337            listEditor.setEditable(false);
338            listEditor.setToolTipText(null);
339            listEditor.removeActionListener(al);
340            listEditor.setModel(
341                new DefaultComboBoxModel(
342                    MondrianGuiDef.Level._hideMemberIf_values));
343            listEditor.setSelectedItem((String) value);
344            activeEditor = listEditor;
345
346        } else if (targetClassz == MondrianGuiDef.Level.class
347                   && propertyName.equals("levelType"))
348        {
349            listEditor.setEditable(false);
350            listEditor.setToolTipText(null);
351            listEditor.removeActionListener(al);
352            listEditor.setModel(
353                new DefaultComboBoxModel(
354                    MondrianGuiDef.Level._levelType_values));
355            listEditor.setSelectedItem((String) value);
356            activeEditor = listEditor;
357
358        } else if (targetClassz == MondrianGuiDef.Level.class
359                   && propertyName.equals("type"))
360        {
361            listEditor.setEditable(false);
362            listEditor.setToolTipText(null);
363            listEditor.removeActionListener(al);
364            listEditor.setModel(
365                new DefaultComboBoxModel(MondrianGuiDef.Level._type_values));
366            listEditor.setSelectedItem((String) value);
367            activeEditor = listEditor;
368
369        } else if (targetClassz == MondrianGuiDef.Level.class
370            && propertyName.equals("internalType"))
371        {
372            listEditor.setEditable(false);
373            listEditor.setToolTipText(null);
374            listEditor.removeActionListener(al);
375            listEditor.setModel(
376                new DefaultComboBoxModel(
377                    MondrianGuiDef.Level._internalType_values));
378            listEditor.setSelectedItem((String) value);
379            activeEditor = listEditor;
380
381        } else if (targetClassz == MondrianGuiDef.Dimension.class
382                   && propertyName.equals("type"))
383        {
384            listEditor.setEditable(false);
385            listEditor.setToolTipText(null);
386            listEditor.removeActionListener(al);
387            listEditor.setModel(
388                new DefaultComboBoxModel(
389                    MondrianGuiDef.Dimension._type_values));
390            listEditor.setSelectedItem((String) value);
391            activeEditor = listEditor;
392
393        } else if (targetClassz == MondrianGuiDef.DimensionUsage.class
394                   && propertyName.equals("source"))
395        {
396            List<String> source = getSource();
397            ComboBoxModel cAllsource =
398                new DefaultComboBoxModel(new Vector<String>(source));
399
400            listEditor.setEditable(true);
401            listEditor.setToolTipText(null);
402            listEditor.removeActionListener(al);
403
404            listEditor.setModel(cAllsource);
405            listEditor.setSelectedItem((String) value);
406            listEditorValue = (String) value;
407            activeEditor = listEditor;
408
409        } else if ((tableModel.target instanceof MondrianGuiDef.Grant
410            || tableModel.target instanceof MondrianGuiDef.MemberGrant)
411            && propertyName.equals("access"))
412        {
413            listEditor.setEditable(false);
414            listEditor.setToolTipText(null);
415            listEditor.removeActionListener(al);
416
417            ComboBoxModel cAccess =
418                new DefaultComboBoxModel(
419                    new String[]{"all", "none"});
420
421            if (targetClassz == MondrianGuiDef.SchemaGrant.class) {
422                cAccess = new DefaultComboBoxModel(
423                    new String[]{
424                        "all", "custom", "none", "all_dimensions"
425                    });
426            } else if (targetClassz == MondrianGuiDef.CubeGrant.class
427                       || targetClassz == MondrianGuiDef.DimensionGrant.class
428                       || targetClassz == MondrianGuiDef.MemberGrant.class)
429            {
430                cAccess =
431                    new DefaultComboBoxModel(
432                        new String[]{"all", "custom", "none"});
433
434            } else if (targetClassz == MondrianGuiDef.HierarchyGrant.class
435                || targetClassz == MondrianGuiDef.DimensionGrant.class)
436            {
437                cAccess = new DefaultComboBoxModel(
438                    new String[]{
439                        "all", "custom", "none"
440                    });
441            }
442            listEditor.setModel(cAccess);
443
444            listEditor.setSelectedItem((String) value);
445            activeEditor = listEditor;
446
447        } else if (targetClassz == MondrianGuiDef.HierarchyGrant.class
448            && propertyName.equals("rollupPolicy")) {
449            ComboBoxModel cRollupPolicy =
450                new DefaultComboBoxModel(
451                    new String[]{"full", "partial", "hidden"});
452            listEditor.setModel(cRollupPolicy);
453            listEditor.setSelectedItem(value);
454            activeEditor = listEditor;
455        } else if (targetClassz == MondrianGuiDef.DimensionGrant.class
456                    && propertyName.equals("dimension"))
457        {
458            List<String> source = getDimensions();
459            ComboBoxModel cAllsource =
460                new DefaultComboBoxModel(new Vector<String>(source));
461
462            listEditor.setEditable(false);
463            listEditor.setToolTipText(null);
464            listEditor.removeActionListener(al);
465
466            listEditor.setModel(cAllsource);
467            listEditor.setSelectedItem((String) value);
468            listEditorValue = (String) value;
469            activeEditor = listEditor;
470
471        } else if (targetClassz == MondrianGuiDef.HierarchyGrant.class
472                       && propertyName.equals("hierarchy"))
473        {
474            List<String> source = getHierarchies();
475            ComboBoxModel cAllsource =
476                new DefaultComboBoxModel(new Vector<String>(source));
477
478            listEditor.setEditable(false);
479            listEditor.setToolTipText(null);
480            listEditor.removeActionListener(al);
481
482            listEditor.setModel(cAllsource);
483            listEditor.setSelectedItem((String) value);
484            listEditorValue = (String) value;
485            activeEditor = listEditor;
486
487        } else if ((targetClassz == MondrianGuiDef.HierarchyGrant.class
488                    && (propertyName.equals("topLevel")
489                        || propertyName.equals("bottomLevel"))))
490        {
491            List<String> source = getLevels(
492                ((MondrianGuiDef.HierarchyGrant) tableModel.target).hierarchy);
493            ComboBoxModel cAllsource =
494                new DefaultComboBoxModel(new Vector<String>(source));
495
496            listEditor.setEditable(false);
497            listEditor.setToolTipText(null);
498            listEditor.removeActionListener(al);
499
500            listEditor.setModel(cAllsource);
501            listEditor.setSelectedItem((String) value);
502            listEditorValue = (String) value;
503            activeEditor = listEditor;
504
505        } else if (((targetClassz == MondrianGuiDef.VirtualCubeDimension.class
506                     || targetClassz == MondrianGuiDef.VirtualCubeMeasure.class)
507                    && propertyName.equals("cubeName"))
508                   || (targetClassz == MondrianGuiDef.CubeGrant.class
509                       && propertyName.equals("cube")))
510        {
511            List<String> source = getCubes();
512            ComboBoxModel cAllsource =
513                new DefaultComboBoxModel(new Vector<String>(source));
514
515            listEditor.setEditable(false);
516            listEditor.setToolTipText(null);
517            listEditor.removeActionListener(al);
518
519            listEditor.setModel(cAllsource);
520            listEditor.setSelectedItem((String) value);
521            listEditorValue = (String) value;
522            activeEditor = listEditor;
523        } else if ((targetClassz == MondrianGuiDef.Dimension.class
524                    && propertyName.equals("foreignKey"))
525                   || (targetClassz == MondrianGuiDef.DimensionUsage.class
526                       && propertyName.equals("foreignKey"))
527                   || (targetClassz == MondrianGuiDef.Measure.class
528                       && propertyName.equals("column")))
529        {
530            Vector<String> fks = new Vector<String>(
531                jdbcMetaData.getFactTableFKs(
532                    selectedFactTableSchema, selectedFactTable));
533            fks.add(
534                0, getResourceConverter().getString(
535                    "schemaPropertyCellEditor.allColumns",
536                    "<< All Columns >>"));
537            Vector<String> allcols = new Vector<String>(
538                jdbcMetaData.getAllColumns(
539                    selectedFactTableSchema, selectedFactTable));
540            ComboBoxModel cFks = new DefaultComboBoxModel(fks);
541
542            listEditor.setEditable(true);
543            listEditor.setToolTipText(null);
544            listEditor.removeActionListener(al);
545            if ((fks.size() > 1) && propertyName.equals("foreignKey")) {
546                allcols.add(
547                    0,
548                    getResourceConverter().getString(
549                        "schemaPropertyCellEditor.foreignKeys",
550                        "<< Foreign keys >>"));
551                ComboBoxModel cAllcols = new DefaultComboBoxModel(allcols);
552                listEditor.setModel(cFks);
553                selOptions = cFks;
554                allOptions = cAllcols;
555                listEditor.addActionListener(al);
556            } else {
557                ComboBoxModel cAllcols = new DefaultComboBoxModel(allcols);
558                listEditor.setModel(cAllcols);
559            }
560
561            listEditor.setSelectedItem((String) value);
562            listEditorValue = (String) value;
563            activeEditor = listEditor;
564        } else if (targetClassz == MondrianGuiDef.Hierarchy.class
565                   && propertyName.equals("primaryKey"))
566        {
567            MondrianGuiDef.Hierarchy hProps =
568                (MondrianGuiDef.Hierarchy) tableModel.getValue();
569            String pkTable = hProps.primaryKeyTable;
570
571            String schemaName = null;
572
573            String pk = "";
574            List<String> allcols;
575
576            MondrianGuiDef.RelationOrJoin relation = hProps.relation;
577            if (relation instanceof MondrianGuiDef.Table) {
578                pkTable = ((MondrianGuiDef.Table) relation).name;
579                schemaName = ((MondrianGuiDef.Table) relation).schema;
580                pk = jdbcMetaData.getTablePK(schemaName, pkTable);
581            } else if (relation instanceof MondrianGuiDef.Join) {
582                String[] schemaAndTable =
583                    SchemaExplorer.getTableNameForAlias(
584                        hProps.relation, pkTable);
585                schemaName = schemaAndTable[0];
586                pkTable = schemaAndTable[1];
587            }
588
589            if (relation instanceof MondrianGuiDef.Table
590                || relation instanceof MondrianGuiDef.Join)
591            {
592                allcols = jdbcMetaData.getAllColumns(schemaName, pkTable);
593                pk = jdbcMetaData.getTablePK(schemaName, pkTable);
594            } else {
595                allcols = Collections.emptyList();
596            }
597
598            ComboBoxModel cAllcols =
599                new DefaultComboBoxModel(new Vector<String>(allcols));
600
601            listEditor.setEditable(true);
602            listEditor.setToolTipText(null);
603            listEditor.removeActionListener(al);
604
605            listEditor.setModel(cAllcols);
606            if (value == null || ((String) value).equals("")) {
607                listEditor.setSelectedItem(pk);
608            } else {
609                listEditor.setSelectedItem((String) value);
610                listEditorValue = (String) value;
611            }
612            activeEditor = listEditor;
613        } else if ((targetClassz == MondrianGuiDef.Level.class
614                    && propertyName.equals("column"))
615                   || (targetClassz == MondrianGuiDef.Level.class
616                       && propertyName.equals("nameColumn"))
617                   || (targetClassz == MondrianGuiDef.Level.class
618                       && propertyName.equals("parentColumn"))
619                   || (targetClassz == MondrianGuiDef.Level.class
620                       && propertyName.equals("ordinalColumn"))
621                   || (targetClassz == MondrianGuiDef.Level.class
622                       && propertyName.equals("captionColumn"))
623                   || (targetClassz == MondrianGuiDef.Closure.class
624                       && propertyName.equals("parentColumn"))
625                   || (targetClassz == MondrianGuiDef.Closure.class
626                       && propertyName.equals("childColumn"))
627                   || (targetClassz == MondrianGuiDef.Property.class
628                       && propertyName.equals("column")))
629        {
630            MondrianGuiDef.Level lProps;
631            if (targetClassz == MondrianGuiDef.Level.class) {
632                lProps = (MondrianGuiDef.Level) tableModel.getValue();
633            } else {
634                lProps = (MondrianGuiDef.Level) this.getParentObject();
635            }
636
637            String schemaName = null;
638            String lTable = lProps.table;
639            List<String> allcols;
640
641            // Sets the corresponding columns on the selection dropdown for the
642            // specified table.
643            if (targetClassz == MondrianGuiDef.Level.class && parent != null) {
644                if (parent instanceof MondrianGuiDef.Hierarchy) {
645                    MondrianGuiDef.RelationOrJoin relation =
646                        ((MondrianGuiDef.Hierarchy) parent).relation;
647                    if (relation instanceof MondrianGuiDef.Table) {
648                        lTable = ((MondrianGuiDef.Table) relation).name;
649                        schemaName = ((MondrianGuiDef.Table) relation).schema;
650                    } else if (relation instanceof MondrianGuiDef.Join) {
651                        String[] schemaAndTable =
652                            SchemaExplorer.getTableNameForAlias(
653                                relation, lTable);
654                        schemaName = schemaAndTable[0];
655                        lTable = schemaAndTable[1];
656                    }
657                }
658            }
659            if (lTable != null) {
660                allcols = jdbcMetaData.getAllColumns(schemaName, lTable);
661            } else {
662                allcols = Collections.emptyList();
663            }
664            ComboBoxModel cAllcols =
665                new DefaultComboBoxModel(new Vector<String>(allcols));
666
667            listEditor.setEditable(true);
668            listEditor.setToolTipText(null);
669            listEditor.removeActionListener(al);
670
671            listEditor.setModel(cAllcols);
672            listEditor.setSelectedItem((String) value);
673            listEditorValue = (String) value;
674            activeEditor = listEditor;
675
676        } else if (targetClassz == MondrianGuiDef.Property.class
677                   && propertyName.equals("type"))
678        {
679            listEditor.setEditable(false);
680            listEditor.setToolTipText(null);
681            listEditor.removeActionListener(al);
682            listEditor.setModel(
683                new DefaultComboBoxModel(MondrianGuiDef.Property._type_values));
684            listEditor.setSelectedItem((String) value);
685            activeEditor = listEditor;
686
687        } else if ((targetClassz == MondrianGuiDef.AggFactCount.class
688                    && propertyName.equals("column"))
689                   || (targetClassz == MondrianGuiDef.AggIgnoreColumn.class
690                       && propertyName.equals("column"))
691                   || (targetClassz == MondrianGuiDef.AggLevel.class
692                       && propertyName.equals("column"))
693                   || (targetClassz == MondrianGuiDef.AggMeasure.class
694                       && propertyName.equals("column"))
695                   || (targetClassz == MondrianGuiDef.AggForeignKey.class
696                       && propertyName.equals("factColumn"))
697                   || (targetClassz == MondrianGuiDef.AggForeignKey.class
698                       && propertyName.equals("aggColumn")))
699        {
700            List<String> allcols = jdbcMetaData.getAllColumns(null, null);
701            ComboBoxModel cAllcols =
702                new DefaultComboBoxModel(new Vector<String>(allcols));
703
704            listEditor.setEditable(true);
705            listEditor.setToolTipText(null);
706            listEditor.removeActionListener(al);
707
708            listEditor.setModel(cAllcols);
709            listEditor.setSelectedItem((String) value);
710            listEditorValue = (String) value;
711            activeEditor = listEditor;
712
713        } else if (targetClassz == MondrianGuiDef.Table.class && propertyName
714            .equals("schema"))
715        {
716            List<String> allschemas = jdbcMetaData.getAllSchemas();
717            ComboBoxModel cAllschemas =
718                new DefaultComboBoxModel(new Vector<String>(allschemas));
719
720            listEditor.setEditable(true);
721            listEditor.setToolTipText(null);
722            listEditor.removeActionListener(al);
723
724            listEditor.setModel(cAllschemas);
725            listEditor.setSelectedItem((String) value);
726            listEditorValue = (String) value;
727            activeEditor = listEditor;
728        } else if (currentRelation != null
729                   && nonTableRelation
730                   && ((targetClassz == MondrianGuiDef.Hierarchy.class
731                        && propertyName.equals("primaryKeyTable"))
732                       || (targetClassz == MondrianGuiDef.Level.class
733                           && propertyName.equals("table"))))
734        {
735            // Can't set a table on a non table relation
736            listEditor.setEditable(false);
737            listEditor.setToolTipText(null);
738            listEditor.removeActionListener(al);
739            activeEditor = listEditor;
740        } else if ((targetClassz == MondrianGuiDef.Table.class
741                    && propertyName.equals("name"))
742                   || (targetClassz == MondrianGuiDef.Hierarchy.class
743                       && propertyName.equals("primaryKeyTable"))
744                   || (targetClassz == MondrianGuiDef.Level.class
745                       && propertyName.equals("table")))
746        {
747            String schema = "";
748            if (targetClassz == MondrianGuiDef.Table.class) {
749                MondrianGuiDef.Table tProps =
750                    (MondrianGuiDef.Table) tableModel.getValue();
751                schema = tProps.schema;
752            }
753            Vector<String> factTables =
754                new Vector<String>(jdbcMetaData.getFactTables(schema));
755            Vector<String> allTablesMinusFact =
756                new Vector<String>(
757                    jdbcMetaData.getAllTables(
758                        schema, selectedFactTable));
759            Vector<String> allTables =
760                new Vector<String>(jdbcMetaData.getAllTables(schema));
761            Vector<String> dimeTables =
762                new Vector<String>(
763                    jdbcMetaData.getDimensionTables(
764                        schema, selectedFactTable));
765
766            // suggestive fact tables
767            ComboBoxModel cFactTables =
768                new DefaultComboBoxModel(factTables);
769
770            // all tables of selected schema
771            ComboBoxModel cAllTables = new DefaultComboBoxModel(
772                (allTablesMinusFact.size() > 0)
773                    ? allTablesMinusFact
774                    : allTables);
775
776            // suggestive dimension tables based on selected fact table
777            ComboBoxModel cDimeTables =
778                new DefaultComboBoxModel(dimeTables);
779
780            // Sets the corresponding join tables on selection dropdown when
781            // using joins.
782            if (targetClassz == MondrianGuiDef.Level.class
783                || targetClassz == MondrianGuiDef.Hierarchy.class)
784            {
785                MondrianGuiDef.RelationOrJoin relation = null;
786                if (parent != null
787                    && parent instanceof MondrianGuiDef.Hierarchy)
788                {
789                    relation = ((MondrianGuiDef.Hierarchy) parent).relation;
790                } else {
791                    relation =
792                        ((MondrianGuiDef.Hierarchy) tableModel.target).relation;
793                }
794                if (relation instanceof MondrianGuiDef.Join) {
795                    TreeSet<String> joinTables = new TreeSet<String>();
796                    // getTableNamesForJoin calls itself recursively and
797                    // collects table names in joinTables.
798                    SchemaExplorer.getTableNamesForJoin(relation, joinTables);
799                    cAllTables =
800                        new DefaultComboBoxModel(
801                            new Vector<String>(
802                                joinTables));
803                }
804            }
805
806            listEditor.setEditable(true);
807            listEditor.setToolTipText(null);
808            listEditor.removeActionListener(al);
809            listEditor.setModel(cAllTables);
810            allOptions = cAllTables;
811            boolean toggleModel = false;
812            if (parentClassz == MondrianGuiDef.Cube.class) {
813                cAllTables = new DefaultComboBoxModel(allTables);
814                allOptions = cAllTables;
815                if (factTables.size() > 0) {
816                    ((DefaultComboBoxModel) cFactTables).insertElementAt(
817                        workbench.getResourceConverter().getString(
818                            "schemaPropertyCellEditor.allTables",
819                            "<< All Tables >>"), 0);
820                    ((DefaultComboBoxModel) cAllTables).insertElementAt(
821                        workbench.getResourceConverter().getString(
822                            "schemaPropertyCellEditor.factTables",
823                            "<< Fact Tables >>"), 0);
824                    listEditor.setModel(cFactTables);
825                    selOptions = cFactTables;
826                    toggleModel = true;
827                }
828            } else {
829                if (dimeTables.size() > 0) {
830                    ((DefaultComboBoxModel) cDimeTables).insertElementAt(
831                        workbench.getResourceConverter().getString(
832                            "schemaPropertyCellEditor.allTables",
833                            "<< All Tables >>"), 0);
834                    ((DefaultComboBoxModel) cAllTables).insertElementAt(
835                        workbench.getResourceConverter().getString(
836                            "schemaPropertyCellEditor.dimensionTables",
837                            "<< Dimension Tables >>"), 0);
838                    listEditor.setModel(cDimeTables);
839                    selOptions = cDimeTables;
840                    toggleModel = true;
841                }
842            }
843
844            if (toggleModel) {
845                listEditor.addActionListener(al);
846            }
847            listEditor.setSelectedItem((String) value);
848            listEditorValue = (String) value;
849            activeEditor = listEditor;
850            // Disables table selection when not using joins.
851            if ((targetClassz == MondrianGuiDef.Level.class
852                 && propertyName.equals(SchemaExplorer.DEF_LEVEL[1])
853                 && parent != null)
854                || (targetClassz == MondrianGuiDef.Hierarchy.class
855                    && propertyName.equals(SchemaExplorer.DEF_HIERARCHY[7])
856                    && parent != null))
857            {
858                MondrianGuiDef.RelationOrJoin relation = null;
859                if (parent instanceof MondrianGuiDef.Hierarchy) {
860                    relation = ((MondrianGuiDef.Hierarchy) parent).relation;
861                } else if (parent instanceof MondrianGuiDef.Dimension) {
862                    relation =
863                        ((MondrianGuiDef.Hierarchy) tableModel.target).relation;
864                }
865                if (relation instanceof MondrianGuiDef.Table) {
866                    activeEditor = stringEditor;
867                    stringEditor.setText((String) value);
868                }
869            }
870        } else if (propertyName.equals("cdata")) {
871            try {
872                cdataTextArea.read(new StringReader((String) value), null);
873            } catch (Exception ex) {
874            }
875
876            activeEditor = jScrollPaneCDATA;
877        } else if (value instanceof String) {
878            activeEditor = stringEditor;
879            stringEditor.setText((String) value);
880        } else if (value instanceof Boolean) {
881            activeEditor = booleanEditor;
882            booleanEditor.setSelected((Boolean) value);
883        } else if (value instanceof Integer) {
884            activeEditor = integerEditor;
885            integerEditor.setText((String) value);
886        } else if (value == null) {
887            value = "";
888            activeEditor = stringEditor;
889            stringEditor.setText((String) value);
890        } else if (value.getClass() == MondrianGuiDef.Join.class) {
891            SchemaPropertyCellEditor spce =
892                new SchemaPropertyCellEditor(workbench);
893            tableEditor.setDefaultEditor(Object.class, spce);
894            SchemaPropertyCellRenderer spcr =
895                new SchemaPropertyCellRenderer(workbench);
896            tableEditor.setDefaultRenderer(Object.class, spcr);
897            PropertyTableModel ptm =
898                new PropertyTableModel(
899                    workbench, value, SchemaExplorer.DEF_JOIN);
900            tableEditor.setModel(ptm);
901            activeEditor = tableEditor;
902        } else if (value.getClass() == MondrianGuiDef.NameExpression.class) {
903            return null;
904        } else if (value.getClass() == MondrianGuiDef.RelationOrJoin.class) {
905            // REVIEW: I don't think this code will ever be executed, because
906            // class RelationOrJoin is abstract.
907            SchemaPropertyCellEditor spce =
908                new SchemaPropertyCellEditor(workbench);
909            tableEditor.setDefaultEditor(Object.class, spce);
910            SchemaPropertyCellRenderer spcr =
911                new SchemaPropertyCellRenderer(workbench);
912            tableEditor.setDefaultRenderer(Object.class, spcr);
913            PropertyTableModel ptm =
914                new PropertyTableModel(
915                    workbench, value, SchemaExplorer.DEF_RELATION);
916            tableEditor.setModel(ptm);
917            activeEditor = tableEditor;
918            return null;
919        } else if (value.getClass() == MondrianGuiDef.OrdinalExpression.class) {
920            SchemaPropertyCellEditor spce =
921                new SchemaPropertyCellEditor(workbench);
922            tableEditor.setDefaultEditor(Object.class, spce);
923            SchemaPropertyCellRenderer spcr =
924                new SchemaPropertyCellRenderer(workbench);
925            tableEditor.setDefaultRenderer(Object.class, spcr);
926            PropertyTableModel ptm =
927                new PropertyTableModel(
928                    workbench,
929                    ((MondrianGuiDef.OrdinalExpression) value).expressions[0],
930                    SchemaExplorer.DEF_SQL);
931            ptm.setParentTarget(((PropertyTableModel) table.getModel()).target);
932            tableEditor.setModel(ptm);
933            activeEditor = tableEditor;
934        } else if (value.getClass() == MondrianGuiDef.CaptionExpression.class) {
935            SchemaPropertyCellEditor spce =
936                new SchemaPropertyCellEditor(workbench);
937            tableEditor.setDefaultEditor(Object.class, spce);
938            SchemaPropertyCellRenderer spcr =
939                new SchemaPropertyCellRenderer(workbench);
940            tableEditor.setDefaultRenderer(Object.class, spcr);
941            PropertyTableModel ptm =
942                new PropertyTableModel(
943                    workbench,
944                    ((MondrianGuiDef.CaptionExpression) value).expressions[0],
945                    SchemaExplorer.DEF_SQL);
946            ptm.setParentTarget(((PropertyTableModel) table.getModel()).target);
947            tableEditor.setModel(ptm);
948            activeEditor = tableEditor;
949        } else if (value.getClass() == MondrianGuiDef.Formula.class) {
950            SchemaPropertyCellEditor spce =
951                new SchemaPropertyCellEditor(
952                    workbench, jdbcMetaData);
953            tableEditor.setDefaultEditor(Object.class, spce);
954            SchemaPropertyCellRenderer spcr =
955                new SchemaPropertyCellRenderer(workbench);
956            tableEditor.setDefaultRenderer(Object.class, spcr);
957            PropertyTableModel ptm =
958                new PropertyTableModel(
959                    workbench, value, SchemaExplorer.DEF_FORMULA);
960            tableEditor.setModel(ptm);
961            tableEditor.getColumnModel().getColumn(0).setMaxWidth(100);
962            tableEditor.getColumnModel().getColumn(0).setMinWidth(100);
963            activeEditor = tableEditor;
964        } else if (value.getClass()
965                   == MondrianGuiDef.CalculatedMemberProperty.class)
966        {
967            SchemaPropertyCellEditor spce =
968                new SchemaPropertyCellEditor(workbench, jdbcMetaData);
969            tableEditor.setDefaultEditor(Object.class, spce);
970            SchemaPropertyCellRenderer spcr =
971                new SchemaPropertyCellRenderer(workbench);
972            tableEditor.setDefaultRenderer(Object.class, spcr);
973            PropertyTableModel ptm =
974                new PropertyTableModel(
975                    workbench,
976                    value,
977                    SchemaExplorer.DEF_CALCULATED_MEMBER_PROPERTY);
978            tableEditor.setModel(ptm);
979            tableEditor.getColumnModel().getColumn(0).setMaxWidth(100);
980            tableEditor.getColumnModel().getColumn(0).setMinWidth(100);
981            activeEditor = tableEditor;
982        } else if (value.getClass() == MondrianGuiDef.Table.class) {
983            SchemaPropertyCellEditor spce =
984                new SchemaPropertyCellEditor(workbench, jdbcMetaData);
985            // Adding cell editing stopped listeners to nested property of type
986            // table so that any change in value of table fields are reflected
987            // in tree.
988            for (int i = listeners.size() - 1; i >= 0; i--) {
989                spce.addCellEditorListener(listeners.get(i));
990            }
991            tableEditor.setDefaultEditor(Object.class, spce);
992            SchemaPropertyCellRenderer spcr = new SchemaPropertyCellRenderer(
993                workbench);
994            tableEditor.setDefaultRenderer(Object.class, spcr);
995            PropertyTableModel ptm = new PropertyTableModel(
996                workbench, value, SchemaExplorer.DEF_TABLE);
997            ptm.setFactTable(selectedFactTable);
998            if (targetClassz == MondrianGuiDef.Cube.class) {
999                ptm.setParentTarget(
1000                    ((PropertyTableModel) table.getModel()).target);
1001            }
1002            tableEditor.setModel(ptm);
1003            tableEditor.getColumnModel().getColumn(0).setMaxWidth(100);
1004            tableEditor.getColumnModel().getColumn(0).setMinWidth(100);
1005            activeEditor = tableEditor;
1006        } else if (value.getClass() == MondrianGuiDef.AggFactCount.class) {
1007            SchemaPropertyCellEditor spce = new SchemaPropertyCellEditor(
1008                workbench, jdbcMetaData);
1009            // Adding cell editing stopped listeners to nested property of type
1010            // table so that any change in value of table fields are reflected
1011            // in tree.
1012            for (int i = listeners.size() - 1; i >= 0; i--) {
1013                spce.addCellEditorListener(listeners.get(i));
1014            }
1015            tableEditor.setDefaultEditor(Object.class, spce);
1016            SchemaPropertyCellRenderer spcr = new SchemaPropertyCellRenderer(
1017                workbench);
1018            tableEditor.setDefaultRenderer(Object.class, spcr);
1019            PropertyTableModel ptm = new PropertyTableModel(
1020                workbench, value, SchemaExplorer.DEF_AGG_FACT_COUNT);
1021            ptm.setFactTable(selectedFactTable);
1022            tableEditor.setModel(ptm);
1023            tableEditor.getColumnModel().getColumn(0).setMaxWidth(100);
1024            tableEditor.getColumnModel().getColumn(0).setMinWidth(100);
1025            activeEditor = tableEditor;
1026        } else if (value.getClass() == MondrianGuiDef.Closure.class) {
1027            SchemaPropertyCellEditor spce =
1028                new SchemaPropertyCellEditor(workbench, jdbcMetaData);
1029            // Adding cell editing stopped listeners to nested property of type
1030            // table so that any change in value of table fields are reflected
1031            // in tree.
1032            for (int i = listeners.size() - 1; i >= 0; i--) {
1033                spce.addCellEditorListener(listeners.get(i));
1034            }
1035            tableEditor.setDefaultEditor(Object.class, spce);
1036            SchemaPropertyCellRenderer spcr =
1037                new SchemaPropertyCellRenderer(workbench);
1038            tableEditor.setDefaultRenderer(Object.class, spcr);
1039            PropertyTableModel ptm =
1040                new PropertyTableModel(
1041                    workbench, value, SchemaExplorer.DEF_CLOSURE);
1042            ptm.setFactTable(selectedFactTable);
1043            if (targetClassz == MondrianGuiDef.Level.class) {
1044                ptm.setParentTarget(
1045                    ((PropertyTableModel) table.getModel()).target);
1046            }
1047            tableEditor.setModel(ptm);
1048            tableEditor.getColumnModel().getColumn(0).setMaxWidth(100);
1049            tableEditor.getColumnModel().getColumn(0).setMinWidth(100);
1050            spcr.setTableRendererHeight(tableEditor, null);
1051            activeEditor = tableEditor;
1052        } else if (value.getClass() == MondrianGuiDef.Property.class) {
1053            SchemaPropertyCellEditor spce =
1054                new SchemaPropertyCellEditor(workbench);
1055            tableEditor.setDefaultEditor(Object.class, spce);
1056            SchemaPropertyCellRenderer spcr =
1057                new SchemaPropertyCellRenderer(workbench);
1058            tableEditor.setDefaultRenderer(Object.class, spcr);
1059            PropertyTableModel ptm =
1060                new PropertyTableModel(
1061                    workbench, value, SchemaExplorer.DEF_PROPERTY);
1062            tableEditor.setModel(ptm);
1063            activeEditor = tableEditor;
1064        } else {
1065            value = "";
1066            activeEditor = stringEditor;
1067            stringEditor.setText((String) value);
1068        }
1069        activeEditor.setVisible(true);
1070
1071        setOriginalValue();
1072
1073        table.changeSelection(row, column, false, false);
1074        activeEditor.setBackground(new java.awt.Color(224, 249, 255));
1075        activeEditor.requestFocusInWindow();
1076        return activeEditor;
1077    }
1078
1079    /**
1080     * save original value to see whether it changed
1081     */
1082    private void setOriginalValue() {
1083        if (activeEditor == stringEditor) {
1084            originalValue = stringEditor.getText();
1085        } else if (activeEditor == booleanEditor) {
1086            originalValue = booleanEditor.isSelected();
1087        } else if (activeEditor == listEditor) {
1088            if (listEditor.isEditable()) {
1089                // returns the edited value from combox box
1090                originalValue = listEditor.getEditor().getItem();
1091            } else {
1092                if (listEditor.getSelectedItem() == noSelect) {
1093                    originalValue = null;  // blank selection
1094                }
1095                // returns the selected value from combox box
1096                originalValue = listEditor.getSelectedItem();
1097            }
1098        } else if (activeEditor == tableEditor) {
1099            originalValue =
1100                ((PropertyTableModel) tableEditor.getModel()).getValue();
1101        } else if (activeEditor == jScrollPaneCDATA) {
1102            Writer cdataTextAreaStr = new StringWriter();
1103            try {
1104                cdataTextArea.write(cdataTextAreaStr);
1105            } catch (Exception ex) {
1106            }
1107            originalValue = cdataTextAreaStr.toString();
1108        }
1109    }
1110
1111    /**
1112     * Adds a listener to the list that's notified when the editor
1113     * stops, or cancels editing.
1114     *
1115     * @param l the CellEditorListener
1116     */
1117    public void addCellEditorListener(CellEditorListener l) {
1118        listeners.add(l);
1119    }
1120
1121    /**
1122     * Tells the editor to cancel editing and not accept any partially
1123     * edited value.
1124     */
1125    public void cancelCellEditing() {
1126        if (activeEditor != null) {
1127            activeEditor.setVisible(false);
1128            fireEditingCancelled();
1129        }
1130    }
1131
1132    /**
1133     * Returns the value contained in the editor.
1134     *
1135     * @return the value contained in the editor
1136     */
1137    public Object getCellEditorValue() {
1138        if (activeEditor == stringEditor) {
1139            return stringEditor.getText();
1140        } else if (activeEditor == booleanEditor) {
1141            return booleanEditor.isSelected();
1142        } else if (activeEditor == listEditor) {
1143            if (listEditor.isEditable()) {
1144                // returns the edited value from combox box
1145                return listEditor.getEditor().getItem();
1146            } else {
1147                if (listEditor.getSelectedItem() == noSelect) {
1148                    return null;  // blank selection
1149                }
1150                // returns the selected value from combox box
1151                return listEditor.getSelectedItem();
1152            }
1153        } else if (activeEditor == tableEditor) {
1154            return ((PropertyTableModel) tableEditor.getModel()).getValue();
1155        } else if (activeEditor == jScrollPaneCDATA) {
1156            Writer cdataTextAreaStr = new StringWriter();
1157            try {
1158                cdataTextArea.write(cdataTextAreaStr);
1159            } catch (Exception ex) {
1160            }
1161            return cdataTextAreaStr.toString();
1162        }
1163
1164        return null;
1165    }
1166
1167    /**
1168     * Asks the editor if it can start editing using <code>anEvent</code>.
1169     * <code>anEvent</code> is in the invoking component coordinate system.
1170     * The editor can not assume the Component returned by
1171     * <code>getCellEditorComponent</code> is installed.  This method
1172     * is intended for the use of client to avoid the cost of setting up
1173     * and installing the editor component if editing is not possible.
1174     * If editing can be started this method returns true.
1175     *
1176     * @param anEvent the event the editor should use to consider
1177     *                whether to begin editing or not
1178     * @return true if editing can be started
1179     * @see #shouldSelectCell
1180     */
1181    public boolean isCellEditable(EventObject anEvent) {
1182        return true;
1183    }
1184
1185    /**
1186     * Removes a listener from the list that's notified
1187     *
1188     * @param l the CellEditorListener
1189     */
1190    public void removeCellEditorListener(CellEditorListener l) {
1191        listeners.remove(l);
1192    }
1193
1194    /**
1195     * Returns true if the editing cell should be selected, false otherwise.
1196     * Typically, the return value is true, because is most cases the editing
1197     * cell should be selected.  However, it is useful to return false to
1198     * keep the selection from changing for some types of edits.
1199     * eg. A table that contains a column of check boxes, the user might
1200     * want to be able to change those checkboxes without altering the
1201     * selection.  (See Netscape Communicator for just such an example)
1202     * Of course, it is up to the client of the editor to use the return
1203     * value, but it doesn't need to if it doesn't want to.
1204     *
1205     * @param anEvent the event the editor should use to start
1206     *                editing
1207     * @return true if the editor would like the editing cell to be selected;
1208     *         otherwise returns false
1209     * @see #isCellEditable
1210     */
1211    public boolean shouldSelectCell(EventObject anEvent) {
1212        return true;
1213    }
1214
1215    /**
1216     * Tells the editor to stop editing and accept any partially edited
1217     * value as the value of the editor.  The editor returns false if
1218     * editing was not stopped; this is useful for editors that validate
1219     * and can not accept invalid entries.
1220     *
1221     * @return true if editing was stopped; false otherwise
1222     */
1223    public boolean stopCellEditing() {
1224        if (activeEditor != null) {
1225            /* save the nested table as well */
1226            if (activeEditor == tableEditor) {
1227                if (tableEditor.isEditing()) {
1228                    List<JTable> nestedTableEditors = new ArrayList<JTable>();
1229                    JTable nestedTableEditor = tableEditor;
1230                    // Get the list of nested tables from outer->inner sequence,
1231                    // descending towards innermost nested table
1232                    // so that we can stop the editing in this order.
1233                    while (nestedTableEditor != null) {
1234                        nestedTableEditors.add(nestedTableEditor);
1235                        SchemaPropertyCellEditor sce =
1236                            (SchemaPropertyCellEditor) nestedTableEditor
1237                                .getCellEditor();
1238                        if (sce != null
1239                            && sce.activeEditor == sce.tableEditor
1240                            && sce.tableEditor.isEditing())
1241                        {
1242                            nestedTableEditor = sce.tableEditor; //
1243                            //tableEditor.editingStopped(null);
1244                        } else {
1245                            nestedTableEditor = null;
1246                        }
1247                    }
1248                    for (int i = nestedTableEditors.size() - 1; i >= 0; i--) {
1249                        nestedTableEditors.get(i).editingStopped(null);
1250                    }
1251                }
1252            }
1253            activeEditor.setVisible(false);
1254            fireEditingStopped();
1255        }
1256        return true;
1257    }
1258
1259    protected void fireEditingStopped() {
1260        ChangeEvent ce = new ChangeEvent(this);
1261        for (int i = listeners.size() - 1; i >= 0; i--) {
1262            listeners.get(i).editingStopped(ce);
1263        }
1264    }
1265
1266    protected void fireEditingCancelled() {
1267        ChangeEvent ce = new ChangeEvent(this);
1268        for (int i = listeners.size() - 1; i >= 0; i--) {
1269            listeners.get(i).editingCanceled(ce);
1270        }
1271    }
1272
1273    private List<String> getUdfs() {
1274        List<String> udfs = new ArrayList<String>();
1275        MondrianGuiDef.Schema s = this.getSchema();
1276        if (s != null) {
1277            MondrianGuiDef.UserDefinedFunction[] u = s.userDefinedFunctions;
1278            for (int i = 0; i < u.length; i++) {
1279                if (!(u[i].className == null
1280                      || udfs.contains(u[i].className)))
1281                {
1282                    udfs.add(u[i].className);
1283                }
1284            }
1285        }
1286
1287        return udfs;
1288    }
1289
1290    private List<String> getFormatStrings() {
1291        List<String> fs = new ArrayList<String>();
1292        MondrianGuiDef.Schema s = this.getSchema();
1293        if (s != null) {
1294            MondrianGuiDef.Cube[] c = s.cubes;
1295            for (int i = 0; i < c.length; i++) {
1296                MondrianGuiDef.Measure[] m = c[i].measures;
1297                for (int j = 0; j < m.length; j++) {
1298                    if (!(m[j].formatString == null
1299                          || fs.contains(m[j].formatString)))
1300                    {
1301                        fs.add(m[j].formatString);
1302                    }
1303                }
1304            }
1305        }
1306        return fs;
1307    }
1308
1309    private MondrianGuiDef.Schema getSchema() {
1310        SchemaExplorer se = this.getSchemaExplorer();
1311        return (se == null)
1312            ? null
1313            : se.getSchema();
1314    }
1315
1316    private Object getParentObject() {
1317        SchemaExplorer se = this.getSchemaExplorer();
1318        if (se != null) {
1319            Object po = se.getParentObject();
1320            return po;
1321        }
1322        return null;
1323    }
1324
1325    private SchemaExplorer getSchemaExplorer() {
1326        for (int i = listeners.size() - 1; i >= 0; i--) {
1327            CellEditorListener cel = listeners.get(i);
1328            if (cel instanceof SchemaExplorer) {
1329                return (SchemaExplorer) cel;
1330            }
1331        }
1332        return null;
1333    }
1334
1335    // shared dimensions in schema
1336    private List<String> getSource() {
1337        List<String> source = new ArrayList<String>();
1338        MondrianGuiDef.Schema s = this.getSchema();
1339        if (s != null) {
1340            MondrianGuiDef.Dimension[] u = s.dimensions;
1341            for (int i = 0; i < u.length; i++) {
1342                source.add(u[i].name);
1343            }
1344        }
1345        return source;
1346    }
1347
1348    private List<String> getCubes() {
1349        List<String> source = new ArrayList<String>();
1350        //===source.add(noSelect);
1351        MondrianGuiDef.Schema s = this.getSchema();
1352        if (s != null) {
1353            MondrianGuiDef.Cube[] u = s.cubes;
1354            for (int i = 0; i < u.length; i++) {
1355                source.add(u[i].name);
1356            }
1357        }
1358        return source;
1359    }
1360
1361    private void generatePrimaryKeyTables(Object relation, List<String> v) {
1362        if (relation == null) {
1363            return;
1364        }
1365        if (relation instanceof MondrianGuiDef.Table) {
1366            String sname = ((MondrianGuiDef.Table) relation).schema;
1367            v.add(
1368                ((sname == null || sname.equals(""))
1369                    ? ""
1370                    : sname + "->") + ((MondrianGuiDef.Table) relation).name);
1371            return;
1372        }
1373        MondrianGuiDef.Join currentJoin = (MondrianGuiDef.Join) relation;
1374        generatePrimaryKeyTables(currentJoin.left, v);
1375        generatePrimaryKeyTables(currentJoin.right, v);
1376        return;
1377    }
1378
1379    private List<String> getDimensions() {
1380        List<String> dims = new ArrayList<String>();
1381        Object po = getParentObject(); //cubegrant
1382        if (po != null) {
1383            MondrianGuiDef.CubeGrant parent = (MondrianGuiDef.CubeGrant) po;
1384            if (!(parent.cube == null || parent.cube.equals(""))) {
1385                MondrianGuiDef.Schema s = getSchema();
1386                if (s != null) {
1387                    for (int i = 0; i < s.cubes.length; i++) {
1388                        if (s.cubes[i].name.equals(parent.cube)) {
1389                            dims.add("Measures");
1390                            for (int j = 0; j < s.cubes[i].dimensions.length;
1391                                j++)
1392                            {
1393                                dims.add(s.cubes[i].dimensions[j].name);
1394                            }
1395                            break;
1396                        }
1397                    }
1398                }
1399            }
1400        }
1401        return dims;
1402    }
1403
1404    private List<String> getHierarchies() {
1405        List<String> hiers = new ArrayList<String>();
1406        Object po = getParentObject(); //cubegrant
1407        if (po != null) {
1408            MondrianGuiDef.CubeGrant parent = (MondrianGuiDef.CubeGrant) po;
1409            if (!(parent.cube == null || parent.cube.equals(""))) {
1410                MondrianGuiDef.Schema s = getSchema();
1411                if (s != null) {
1412                    for (int i = 0; i < s.cubes.length; i++) {
1413                        if (s.cubes[i].name.equals(parent.cube)) {
1414                            for (int j = 0; j < s.cubes[i].dimensions.length;
1415                                j++)
1416                            {
1417                                MondrianGuiDef.Dimension sharedDim =
1418                                    lookupDimension(
1419                                        s, s.cubes[i].dimensions[j]);
1420                                NodeDef[] children = sharedDim.getChildren();
1421                                for (int k = 0; k < children.length; k++) {
1422                                    if (children[k] instanceof Hierarchy) {
1423                                        String hname =
1424                                            ((Hierarchy) children[k]).name;
1425                                        if (hname != null) {
1426                                            if (MondrianProperties.instance()
1427                                                .SsasCompatibleNaming.get())
1428                                            {
1429                                                hiers.add(
1430                                                    Util.quoteMdxIdentifier(
1431                                                        s.cubes[i].dimensions[j]
1432                                                            .name)
1433                                                        + "."
1434                                                        + Util
1435                                                            .quoteMdxIdentifier(
1436                                                                hname));
1437                                            } else {
1438                                                hiers.add(
1439                                                    Util.quoteMdxIdentifier(
1440                                                        s.cubes[i].dimensions[j]
1441                                                            .name
1442                                                        + "."
1443                                                        + hname));
1444                                            }
1445                                        } else {
1446                                            hiers.add(Util.quoteMdxIdentifier(
1447                                                s.cubes[i].dimensions[j].name));
1448                                        }
1449                                    }
1450                                }
1451                            }
1452
1453                            break;
1454                        }
1455                    }
1456                }
1457            }
1458        }
1459        return hiers;
1460    }
1461
1462    private String cacheCube = "";
1463    private String cacheHierarchy = "";
1464    private List<String> hlevels = new ArrayList<String>();
1465
1466    private List<String> getLevels(String hierarchy) {
1467        if (hierarchy == null || hierarchy.equals("")) {
1468            return hlevels;
1469        }
1470        List<Id.Segment> segments = Util.parseIdentifier(hierarchy);
1471        if (segments == null || segments.size() == 0) {
1472            return hlevels;
1473        }
1474        if (!MondrianProperties.instance().SsasCompatibleNaming.get()) {
1475            String data = ((Id.NameSegment)segments.get(0)).getName();
1476            // if segment contains a hierarchy
1477            if (data.indexOf(".") >= 0) {
1478                Id.Segment segment = segments.get(0);
1479                // split the segment
1480                segments.clear();
1481                segments.add(new Id.NameSegment(
1482                    data.substring(0, data.indexOf(".")),
1483                    segment.getQuoting()));
1484                segments.add(new Id.NameSegment(
1485                    data.substring(data.indexOf(".") + 1),
1486                    segment.getQuoting()));
1487            }
1488        }
1489        Object po = getParentObject(); //cubegrant
1490        if (po == null) {
1491            return hlevels;
1492        }
1493        MondrianGuiDef.CubeGrant parent = (MondrianGuiDef.CubeGrant) po;
1494        if (parent.cube == null || parent.cube.equals("")) {
1495            return hlevels;
1496        }
1497        if (cacheCube.equals(parent.cube) && cacheHierarchy.equals(hierarchy)) {
1498            return hlevels;
1499        }
1500        hlevels = new ArrayList<String>();
1501        cacheCube = parent.cube;
1502        cacheHierarchy = hierarchy;
1503        MondrianGuiDef.Schema s = getSchema();
1504        if (s == null) {
1505            return hlevels;
1506        }
1507        for (int i = 0; i < s.cubes.length; i++) {
1508            final MondrianGuiDef.Cube cube = s.cubes[i];
1509            if (!cube.name.equals(parent.cube)) {
1510                continue;
1511            }
1512            for (int j = 0; j < cube.dimensions.length; j++) {
1513                final MondrianGuiDef.CubeDimension dimension =
1514                    cube.dimensions[j];
1515                if (!segments.get(0).matches(dimension.name)) {
1516                    continue;
1517                }
1518                MondrianGuiDef.Dimension d = lookupDimension(s, dimension);
1519                NodeDef[] children = d.getChildren();
1520                MondrianGuiDef.Hierarchy hierarchyObj = null;
1521                for (int k = 0; k < children.length; k++) {
1522                    if (children[k] instanceof Hierarchy) {
1523                        if ((segments.size() == 1
1524                                && ((Hierarchy) children[k]).name == null)
1525                            || (segments.size() != 0
1526                                && segments.get(1).matches(
1527                                    ((Hierarchy) children[k]).name)))
1528                        {
1529                            hierarchyObj = (Hierarchy)children[k];
1530                            break;
1531                        }
1532                    }
1533                }
1534                if (hierarchyObj != null) {
1535                    for (int k = 0; k < hierarchyObj.levels.length; k++) {
1536                        hlevels.add(
1537                            hierarchy + "."
1538                            + Util.quoteMdxIdentifier(
1539                                hierarchyObj.levels[k].name));
1540                    }
1541                }
1542            }
1543            break;
1544        }
1545        return hlevels;
1546    }
1547
1548    private static MondrianGuiDef.Dimension lookupDimension(
1549        MondrianGuiDef.Schema schema,
1550        MondrianGuiDef.CubeDimension cubeDimension)
1551    {
1552        if (cubeDimension instanceof MondrianGuiDef.Dimension) {
1553            return (MondrianGuiDef.Dimension) cubeDimension;
1554        } else {
1555            MondrianGuiDef.DimensionUsage dimensionUsage =
1556                (MondrianGuiDef.DimensionUsage) cubeDimension;
1557            for (int m = 0; m < schema.dimensions.length; m++) {
1558                final MondrianGuiDef.Dimension dimension =
1559                    schema.dimensions[m];
1560                if (dimension.name.equals(dimensionUsage.source)) {
1561                    return dimension;
1562                }
1563            }
1564            return null;
1565        }
1566    }
1567
1568    private I18n getResourceConverter() {
1569        return workbench.getResourceConverter();
1570    }
1571
1572    public void setMetaData(JdbcMetaData jdbcMetaData) {
1573        // Called from the SchemaExplorer.resetMetadata(). A call to the
1574        // updateUI() should be made on the owning SchemaFrame to reflect the
1575        // use of the JdbcMetaData being set.
1576        this.jdbcMetaData = jdbcMetaData;
1577    }
1578}
1579
1580// End SchemaPropertyCellEditor.java