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