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-2011 Pentaho and others
009// Copyright (C) 2006-2007 Cincom Systems, Inc.
010// All Rights Reserved.
011*/
012package mondrian.gui;
013
014import org.apache.log4j.Logger;
015
016import java.lang.reflect.Field;
017import java.util.List;
018
019/**
020 * @author sean
021 */
022public class PropertyTableModel extends javax.swing.table.AbstractTableModel {
023
024    private static final Logger LOGGER =
025        Logger.getLogger(PropertyTableModel.class);
026
027    private Object parentTarget; // parent of target
028    private String factTable;   // selected fact table
029    private String factTableSchema;   // selected fact table schema
030
031    // List of names  for this object's siblings already existing in parent'
032    private List<String> names;
033
034    private String errorMsg = null;
035        // error msg when property value could not be set.
036
037    String[] propertyNames;
038    Object target;
039    Workbench workbench;
040
041    public PropertyTableModel(Workbench wb, Object t, String[] pNames) {
042        super();
043        workbench = wb;
044        propertyNames = pNames;
045        target = t;
046    }
047
048    public String getColumnName(int i) {
049        if (i == 0) {
050            return workbench.getResourceConverter().getString(
051                "propertyTableModel.attribute", "Attribute");
052        } else if (i == 1) {
053            return workbench.getResourceConverter().getString(
054                "propertyTableModel.value", "Value");
055        }
056
057        return workbench.getResourceConverter().getString(
058            "propertyTableModel.unknown", "?");
059    }
060
061    // get property name for given row no.
062    public String getRowName(int i) {
063        String pName = propertyNames[i];
064        int j = -1;
065        if ((j = pName.indexOf('|')) != -1) {  //"|"
066            return pName.substring(0, j).trim();
067        } else {
068            return propertyNames[i];
069        }
070    }
071
072    public boolean isCellEditable(int row, int col) {
073        if (col == 1) {
074            Object cellObj = getValueAt(row, col);
075            if (cellObj instanceof MondrianGuiDef.Join) {
076                return false;
077            } else {
078                return true;
079            }
080        }
081
082        return false;
083    }
084
085    /**
086     * Returns the number of columns in the model. A
087     * <code>JTable</code> uses this method to determine how many columns it
088     * should create and display by default.
089     *
090     * @return the number of columns in the model
091     * @see #getRowCount
092     */
093    public int getColumnCount() {
094        return 2; //that's 'Property' and 'Value'
095    }
096
097    /**
098     * Returns the number of rows in the model. A
099     * <code>JTable</code> uses this method to determine how many rows it
100     * should display.  This method should be quick, as it
101     * is called frequently during rendering.
102     *
103     * @return the number of rows in the model
104     * @see #getColumnCount
105     */
106    public int getRowCount() {
107        return propertyNames.length;
108    }
109
110    /**
111     * Returns the value for the cell at <code>columnIndex</code> and
112     * <code>rowIndex</code>.
113     *
114     * @param rowIndex    the row whose value is to be queried
115     * @param columnIndex the column whose value is to be queried
116     * @return the value Object at the specified cell
117     */
118    public Object getValueAt(int rowIndex, int columnIndex) {
119        if (columnIndex == 0) {
120            return propertyNames[rowIndex];
121        } else {
122            try {
123                String pName = propertyNames[rowIndex];
124                if ((pName.indexOf('|')) != -1) {
125                    //"formula | formulaElement.cdata" This is for special cases
126                    // where more than one field refers to the same value.  For
127                    // eg. calculated memeber's formula and formulaelement.cdata
128                    // refers to the same formula string.  These cases arise to
129                    // handle xml standards where an attribute can also appear
130                    // as an xml tag.
131                    Object obj = null;
132
133                    // split field names on | to form an array of property names
134                    // strings that are optional.
135                    String[] pNames = pName.split(
136                        "\\|",
137                        0);
138                    for (int j = 0; j < pNames.length; j++) {
139                        if ((pNames[j].indexOf('.')) != -1) {
140                            // Split string on . to form an array of property
141                            // name within the property name.
142                            String[] pNamesField = pNames[j].trim().split(
143                                "\\.",
144                                0);
145                            if (pNamesField.length > 1) {
146                                Field f =
147                                    target.getClass().getField(
148                                        pNamesField[0].trim());
149                                obj = f.get(target);
150                                if (obj != null) {
151                                    Field f2 = obj.getClass().getField(
152                                        pNamesField[1].trim());
153                                    Object obj2 = f2.get(obj);
154                                    return obj2;
155                                }
156                            }
157                            return null;
158                        } else {
159                            Field f =
160                                target.getClass().getField(pNames[j].trim());
161                            obj = f.get(target);
162                            if (obj != null) {
163                                return obj;
164                            }
165                        }
166                    }
167                    return obj;
168                } else {
169                    // default case where one field refers to one value.
170                    Field f =
171                        target.getClass().getField(propertyNames[rowIndex]);
172
173                    Object obj = f.get(target);
174                    return obj;
175                }
176            } catch (Exception ex) {
177                LOGGER.error("getValueAt(row, index)", ex);
178                return "#ERROR";
179            }
180        }
181    }
182
183    public void setValueAt(Object value, int rowIndex, int columnIndex) {
184        setErrorMsg(null);
185        try {
186            String pName = propertyNames[rowIndex];
187            int i = -1;
188            if ((i = pName.indexOf('|')) != -1) {
189                //"formula | formulaElement.cdata"
190                // save value in the first field name
191                Field f =
192                    target.getClass().getField(
193                        propertyNames[rowIndex].substring(0, i).trim());
194                f.set(target, value);
195                // Delete the value from second and remaining field names. split
196                // field names on | to form an array of property names strings
197                // that are optional.
198                String[] pNames =
199                    pName.split(
200                        "\\|",
201                        0);
202                for (int j = 1; j < pNames.length; j++) {
203                    // Split string on . to form an array of property name
204                    // within the property name.
205                    String[] pNamesField =
206                        pNames[j].trim().split(
207                            "\\.",
208                            0);
209                    Field f2 =
210                        target.getClass().getField(pNamesField[0].trim());
211                    f2.set(target, null);
212                }
213
214//            } else if ((target instanceof MondrianGuiDef.UserDefinedFunction)
215//                && (pName.equals("script")))
216//            {
217//                ((MondrianGuiDef.UserDefinedFunction) target).script =
218//                    (MondrianGuiDef.Script) value;
219//            } else if ((target instanceof MondrianGuiDef.MemberFormatter)
220//                && (pName.equals("script")))
221//            {
222//                ((MondrianGuiDef.MemberFormatter) target).script =
223//                    (MondrianGuiDef.Script) value;
224//            } else if ((target instanceof MondrianGuiDef.CellFormatter)
225//                && (pName.equals("script")))
226//            {
227//                ((MondrianGuiDef.CellFormatter) target).script =
228//                    (MondrianGuiDef.Script) value;
229//            } else if ((target instanceof MondrianGuiDef.PropertyFormatter)
230//                && (pName.equals("script")))
231//            {
232//                ((MondrianGuiDef.PropertyFormatter) target).script =
233//                    (MondrianGuiDef.Script) value;
234
235            } else if ((target instanceof MondrianGuiDef.Level)
236                && (pName.equals("ordinalExp")))
237            {
238                ((MondrianGuiDef.Level) target).ordinalExp.expressions[0] =
239                    (MondrianGuiDef.SQL) value;
240            } else if ((target instanceof MondrianGuiDef.Level)
241                && (pName.equals("captionExp")))
242            {
243                ((MondrianGuiDef.Level) target).captionExp.expressions[0] =
244                    (MondrianGuiDef.SQL) value;
245            } else if ((target instanceof MondrianGuiDef.Table
246                        && pName.equals("name"))
247                       || (target instanceof MondrianGuiDef.Hierarchy
248                           && pName.equals("primaryKeyTable"))
249                       || (target instanceof MondrianGuiDef.Level
250                           && pName.equals("table")))
251            {
252                // updating all table values
253                if (value != null) {
254                    // split and save only if value exists
255                    String[] aValues =
256                        ((String) value).split(JdbcMetaData.LEVEL_SEPARATOR);
257                    if (aValues.length == 2) {
258                        if (target instanceof MondrianGuiDef.Table) {
259                            ((MondrianGuiDef.Table) target).name = aValues[1];
260                            ((MondrianGuiDef.Table) target).schema = aValues[0];
261                            // to refresh the value in schema field also
262                            // alongwith table name
263                            fireTableDataChanged();
264                        } else {
265                            Field f =
266                                target.getClass().getField(
267                                    propertyNames[rowIndex]);
268                            f.set(target, aValues[1]);
269                        }
270                    } else {
271                        // Avoids table="" to be set on schema
272                        Field f =
273                            target.getClass().getField(propertyNames[rowIndex]);
274                        setFieldValue(f, value);
275                    }
276                }
277
278            } else if ((target instanceof MondrianGuiDef.Dimension
279                        && pName.equals("foreignKey"))
280                       || (target instanceof MondrianGuiDef.DimensionUsage
281                           && pName.equals("foreignKey"))
282                       || (target instanceof MondrianGuiDef.Measure
283                           && pName.equals("column"))
284                       || (target instanceof MondrianGuiDef.Hierarchy
285                           && pName.equals("primaryKey"))
286                       || (target instanceof MondrianGuiDef.Level
287                           && pName.equals("column"))
288                       || (target instanceof MondrianGuiDef.Level
289                           && pName.equals("nameColumn"))
290                       || (target instanceof MondrianGuiDef.Level
291                           && pName.equals("ordinalColumn"))
292                       || (target instanceof MondrianGuiDef.Level
293                           && pName.equals("parentColumn"))
294                       || (target instanceof MondrianGuiDef.Level
295                           && pName.equals("captionColumn"))
296                       || (target instanceof MondrianGuiDef.Closure
297                           && pName.equals("parentColumn"))
298                       || (target instanceof MondrianGuiDef.Closure
299                           && pName.equals("childColumn"))
300                       || (target instanceof MondrianGuiDef.Property
301                           && pName.equals("column")))
302            {
303                // updating all column values
304                if (value != null) {
305                    // split and save only if value exists
306                    String[] aValues =
307                        ((String) value).split(JdbcMetaData.LEVEL_SEPARATOR);
308                    Field f =
309                        target.getClass().getField(propertyNames[rowIndex]);
310                    // Avoids *Column="" to be set on schema.  Also remove
311                    // column data type with the final split on a dash.
312                    value = aValues[aValues.length - 1].split(" - ")[0];
313                    setFieldValue(f, value);
314                }
315
316            } else {
317                if (propertyNames[rowIndex].equals("name")
318                    && (!(target instanceof MondrianGuiDef.Table))
319                    && (!value.equals(
320                        target.getClass().getField(
321                            propertyNames[rowIndex]).get(target)))
322                    && duplicateName(value))
323                {
324                    setErrorMsg(
325                        workbench.getResourceConverter().getFormattedString(
326                            "propertyTableModel.duplicateValue.error",
327                            "Error setting name property. {0} already exists",
328                            value.toString()));
329                } else {
330                    Field f =
331                        target.getClass().getField(propertyNames[rowIndex]);
332                    // Avoids property to be set on schema with an empty value.
333                    setFieldValue(f, value);
334                }
335            }
336        } catch (Exception ex) {
337            LOGGER.error("setValueAt(aValue, row, index)", ex);
338        }
339    }
340
341    private void setFieldValue(Field aField, Object aValue)
342        throws IllegalAccessException
343    {
344        if (aValue != null && aValue.toString().trim().length() == 0) {
345            aField.set(target, null);
346        } else {
347            aField.set(target, aValue);
348        }
349    }
350
351    public Object getValue() {
352        return target;
353    }
354
355    public Object getParentTarget() {
356        return parentTarget;
357    }
358
359    public void setParentTarget(Object parentTarget) {
360        this.parentTarget = parentTarget;
361    }
362
363    public String getFactTable() {
364        return factTable;
365    }
366
367    public void setFactTable(String factTable) {
368        this.factTable = factTable;
369    }
370
371    public String getFactTableSchema() {
372        return factTableSchema;
373    }
374
375    public void setFactTableSchema(String factTableSchema) {
376        this.factTableSchema = factTableSchema;
377    }
378
379    private boolean duplicateName(Object aValue) {
380        return (names != null && names.contains(aValue));
381    }
382
383    public List<String> getNames() {
384        return names;
385    }
386
387    public void setNames(List<String> names) {
388        this.names = names;
389    }
390
391    public String getErrorMsg() {
392        return errorMsg;
393    }
394
395    public void setErrorMsg(String errorMsg) {
396        this.errorMsg = errorMsg;
397    }
398}
399
400// End PropertyTableModel.java