001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.framework.ui.view.conditionbuilder;
042:
043: import java.awt.BorderLayout;
044: import java.awt.Component;
045: import java.awt.Dimension;
046: import java.util.Collection;
047: import java.util.Iterator;
048: import java.util.List;
049:
050: import javax.swing.JPanel;
051: import javax.swing.JTabbedPane;
052: import javax.swing.event.ChangeEvent;
053: import javax.swing.event.ChangeListener;
054:
055: import org.netbeans.modules.sql.framework.model.SQLCondition;
056: import org.netbeans.modules.sql.framework.model.SQLObject;
057: import org.netbeans.modules.sql.framework.model.SQLPredicate;
058: import org.netbeans.modules.sql.framework.model.impl.SQLCustomOperatorImpl;
059: import org.netbeans.modules.sql.framework.model.visitors.SQLValidationVisitor;
060: import org.netbeans.modules.sql.framework.ui.view.IGraphViewContainer;
061: import org.openide.DialogDisplayer;
062: import org.openide.NotifyDescriptor;
063: import org.openide.explorer.propertysheet.editors.EnhancedCustomPropertyEditor;
064: import net.java.hulp.i18n.Logger;
065: import com.sun.sql.framework.exception.BaseException;
066: import org.netbeans.modules.etl.logger.Localizer;
067: import org.netbeans.modules.etl.logger.LogUtil;
068:
069: /**
070: * @author Ritesh Adval
071: * @version $Revision$
072: */
073: public class ConditionBuilderView extends JPanel implements
074: EnhancedCustomPropertyEditor {
075:
076: private static transient final Logger mLogger = LogUtil
077: .getLogger(ConditionBuilderView.class.getName());
078: private static transient final Localizer mLoc = Localizer.get();
079:
080: private class TabChangeAdapter implements ChangeListener {
081:
082: private boolean trySync = true;
083:
084: /**
085: * Invoked when the target of the listener has changed its state.
086: *
087: * @param e a ChangeEvent object
088: */
089: public void stateChanged(ChangeEvent e) {
090: if (reLoad) {
091: return;
092: }
093:
094: Component selComp = rightPanel.getSelectedComponent();
095: String nbBundle1 = mLoc
096: .t("PRSR001: Failed to synchronize graph with SQL code - check if condition is valid in text mode.");
097: if (selComp instanceof ConditionBuilderRightPanel) {
098: if (trySync
099: && !ConditionBuilderView.this
100: .synchronizeGraphView()) {
101: DialogDisplayer
102: .getDefault()
103: .notify(
104: new NotifyDescriptor.Message(
105: Localizer.parse(nbBundle1),
106: NotifyDescriptor.INFORMATION_MESSAGE));
107: trySync = false;
108: rightPanel.setSelectedComponent(rightTextPanel);
109: trySync = true;
110: return;
111: }
112:
113: ConditionBuilderRightPanel rightGraphPanel1 = (ConditionBuilderRightPanel) selComp;
114: rightGraphPanel1.setModifiable(!rightTextPanel
115: .isDirty());
116: ConditionBuilderView.this .condContainerObj
117: .setGuiMode(SQLCondition.GUIMODE_GRAPHICAL);
118: } else if (selComp instanceof ConditionBuilderExpRightPanel) {
119: String nbBundle2 = mLoc
120: .t("PRSR001: Failed to synchronize SQL code with graphical mode - check if condition is valid in graphical mode.");
121: if (trySync
122: && !ConditionBuilderView.this
123: .synchronizeSQLCodeView()) {
124: DialogDisplayer
125: .getDefault()
126: .notify(
127: new NotifyDescriptor.Message(
128: Localizer.parse(nbBundle2),
129: NotifyDescriptor.INFORMATION_MESSAGE));
130: trySync = false;
131: rightPanel.setSelectedComponent(rightGraphPanel);
132: trySync = true;
133: return;
134: }
135:
136: ConditionBuilderExpRightPanel rightExpPanel = (ConditionBuilderExpRightPanel) selComp;
137: rightExpPanel.setModifiable(!rightGraphPanel.isDirty());
138: ConditionBuilderView.this .condContainerObj
139: .setGuiMode(SQLCondition.GUIMODE_SQLCODE);
140: }
141: }
142: }
143:
144: private static final String LOG_CATEGORY = ConditionBuilderView.class
145: .getName();
146: private SQLCondition condContainerObj;
147: private IGraphViewContainer editor;
148: private boolean reLoad = false;
149: private ConditionBuilderRightPanel rightGraphPanel;
150: private JTabbedPane rightPanel = new JTabbedPane();
151: private ConditionBuilderExpRightPanel rightTextPanel;
152: private boolean showError = true;
153:
154: /**
155: * Creates a new instance of ConditionBuilderView
156: */
157: public ConditionBuilderView(IGraphViewContainer editor,
158: List tables, SQLCondition cond, int toolbarType) {
159: this (cond);
160: this .editor = editor;
161: initGui(tables, toolbarType);
162: }
163:
164: private ConditionBuilderView() {
165: ConditionViewManager.getDefault()
166: .setCurrentConditionBuilderView(this );
167: }
168:
169: /** Creates a new instance of ConditionBuilderView */
170: private ConditionBuilderView(SQLCondition cond) {
171: this ();
172: if (cond == null) {
173: throw new IllegalArgumentException(
174: "Must supply non null SQLCondition.");
175: }
176: try {
177: condContainerObj = (SQLCondition) cond.cloneSQLObject();
178: } catch (CloneNotSupportedException ex) {
179: mLogger.errorNoloc(mLoc.t(
180: "PRSR156: error cloning the condition{0}",
181: LOG_CATEGORY), ex);
182: return;
183: }
184: }
185:
186: public void doGraphValidation() {
187: rightGraphPanel.doValidation();
188: }
189:
190: public void doSQLCodeValidation() {
191: rightTextPanel.doValidation();
192: }
193:
194: public void doValidation() {
195: if (condContainerObj.getGuiMode() == SQLCondition.GUIMODE_GRAPHICAL) {
196: this .doGraphValidation();
197: } else {
198: this .doSQLCodeValidation();
199: }
200: }
201:
202: /**
203: * Get the customized property value.
204: *
205: * @return the property value
206: * @exception IllegalStateException when the custom property editor does not contain a
207: * valid property value (and thus it should not be set)
208: */
209: public Object getPropertyValue() throws IllegalStateException {
210: // When user exit find out the currently selected mode
211: // then try to synchronize other mode
212: boolean result = setGuiMode();
213: String nbBundle3 = mLoc
214: .t("PRSR001: The condition is not valid. Make sure you correct it.");
215: if (showError && !result) {
216: DialogDisplayer.getDefault().notify(
217: new NotifyDescriptor.Message(Localizer
218: .parse(nbBundle3),
219: NotifyDescriptor.WARNING_MESSAGE));
220: }
221:
222: return condContainerObj;
223: }
224:
225: public SQLCondition getSQLCondition() {
226: return this .condContainerObj;
227: }
228:
229: public boolean isConditionValid() {
230: return (this .rightTextPanel.isDirty()) ? synchronizeGraphView()
231: : synchronizeSQLCodeView();
232: }
233:
234: public boolean isDirty() {
235: return this .rightTextPanel.isDirty()
236: || this .rightGraphPanel.isDirty();
237: }
238:
239: public boolean isShowErrorMsg() {
240: return this .showError;
241: }
242:
243: public void setShowErrorMsg(boolean show) {
244: this .showError = show;
245: }
246:
247: public void showTableTree() {
248: Component c = this .rightPanel.getSelectedComponent();
249: if (c instanceof ConditionBuilderExpRightPanel) {
250: rightTextPanel.showTableTree();
251: }
252: if (c instanceof ConditionBuilderRightPanel) {
253: rightGraphPanel.showTableTree();
254: }
255: }
256:
257: public boolean synchronizeGraphView() {
258: String cond = rightTextPanel.getCondition();
259: boolean customOperator = false;
260:
261: SQLObject obj = null;
262: try {
263: obj = rightTextPanel.getConditionRootPredicate();
264:
265: } catch (Exception ex) {
266: if (ex instanceof BaseException) {
267: if (((BaseException) ex).getErrorCode() == BaseException.OPERATOR_NOT_DEFINED) {
268: customOperator = true;
269: }
270: } else {
271: // Ignore this safely
272: mLogger
273: .errorNoloc(
274: mLoc
275: .t(
276: "PRSR157: Exception occurred while parsing condition{0}",
277: LOG_CATEGORY), ex);
278: }
279: }
280:
281: // For custom operator, disable any further validation
282: // as it can be properly validated only at query time using
283: // test colloboration
284: if (customOperator) {
285: rightGraphPanel.setModifiable(true);
286: rightGraphPanel.setDirty(false);
287: rightTextPanel.setDirty(false);
288: return true;
289: }
290: boolean graphChanged = false;
291: // First check if user has removed the condition
292: if (cond != null && cond.trim().equals("")) {
293: condContainerObj.setConditionText("");
294: rightGraphPanel.clearView();
295: graphChanged = true;
296: // Then check if there is a valid root predicate
297: } else if (obj instanceof SQLPredicate) {
298: SQLValidationVisitor visitor = new SQLValidationVisitor();
299: SQLPredicate predicate = (SQLPredicate) obj;
300: predicate.visit(visitor);
301:
302: // Proceed only if predicate is valid.
303: if (!visitor
304: .hasErrors(ConditionBuilderUtil
305: .filterValidations(visitor
306: .getValidationInfoList()))) {
307: rightGraphPanel.getModel().clearJavaOperators();
308: rightGraphPanel.refresh(obj);
309: graphChanged = true;
310: }
311: }
312:
313: if (graphChanged) {
314: rightGraphPanel.setModifiable(true);
315: rightGraphPanel.setDirty(false);
316: rightTextPanel.setDirty(false);
317: return true;
318: }
319:
320: return false;
321: }
322:
323: public boolean synchronizeSQLCodeView() {
324: SQLObject obj = null;
325: boolean synchronizedSqlText = true;
326: boolean textChanged = false;
327: obj = rightGraphPanel.getConditionRootPredicate();
328:
329: // First check if there is any graph object available
330: // if not then make text empty
331: Collection objC = condContainerObj.getAllObjects();
332: if ((objC == null || objC.size() == 0) && (obj == null)) {
333: rightTextPanel.setCondition("");
334: condContainerObj.setConditionText("");
335: textChanged = true;
336: } else if (obj != null) {
337: rightTextPanel.setCondition(obj.toString());
338: condContainerObj.setConditionText(rightTextPanel
339: .getCondition());
340: textChanged = true;
341: } else if ((objC != null) && (objC.size() > 0)) {
342: // There are objects but failed to get Predicate.
343: Iterator iter = objC.iterator();
344: boolean customOperatorCheck = false;
345: while (iter.hasNext()) {
346: Object localObj = iter.next();
347: if (localObj instanceof SQLCustomOperatorImpl) {
348: customOperatorCheck = true;
349: }
350: }
351: //disabling custom operator validation as
352: //custom operator validation is done only at Test colloboration level
353: if (!customOperatorCheck) {
354: synchronizedSqlText = false;
355: }
356: }
357:
358: if (textChanged) {
359: rightTextPanel.setModifiable(true);
360: rightTextPanel.setDirty(false);
361: rightGraphPanel.setDirty(false);
362: }
363:
364: return synchronizedSqlText;
365: }
366:
367: private void initGui(List tables, int toolbarType) {
368: this .setLayout(new BorderLayout());
369:
370: // Create ConditionBuilderRightPanel
371: rightTextPanel = new ConditionBuilderExpRightPanel(
372: condContainerObj.getConditionText(), editor, tables,
373: toolbarType);
374: rightTextPanel.setMinimumSize(new Dimension(150, 400));
375: rightPanel.add(rightTextPanel, "SQL Code");
376:
377: rightGraphPanel = new ConditionBuilderRightPanel(editor,
378: condContainerObj, tables, toolbarType);
379: rightGraphPanel.setMinimumSize(new Dimension(150, 400));
380: rightPanel.add(rightGraphPanel, "Graphical");
381:
382: // Add listener after adding all the tabs
383: rightPanel.addChangeListener(new TabChangeAdapter());
384:
385: rightTextPanel.setConditionRightGraphView(rightGraphPanel);
386:
387: // set both panel to not dirty initially
388: rightGraphPanel.setDirty(false);
389: rightTextPanel.setDirty(false);
390:
391: this .add(BorderLayout.CENTER, rightPanel);
392:
393: this .setPreferredSize(new Dimension(800, 500));
394:
395: // Now set the default mode which was used last time
396: setGuiState();
397: }
398:
399: private boolean setGuiMode() {
400: boolean result = true;
401: if (this .rightTextPanel.isDirty()
402: || condContainerObj.getGuiMode() == SQLCondition.GUIMODE_SQLCODE) {
403: // If user modifies text view the always try to sync graph view with text view
404: // before exiting from condition builder
405: result = synchronizeGraphView();
406: if (!result) {
407: rightGraphPanel.clearView();
408: }
409: condContainerObj.setGuiMode(SQLCondition.GUIMODE_SQLCODE);
410: condContainerObj.setConditionText(rightTextPanel
411: .getCondition());
412: } else {
413: condContainerObj.setGuiMode(SQLCondition.GUIMODE_GRAPHICAL);
414:
415: // Check if text does not have a valid condition if so then
416: // try to set condition from graph to text
417: result = synchronizeSQLCodeView();
418: if (!result) {
419: rightTextPanel.setCondition("");
420: condContainerObj.setConditionText("");
421: }
422: }
423:
424: return result;
425: }
426:
427: private void setGuiState() {
428: // We are in reload mode so set flag to true
429: reLoad = true;
430: int mode = condContainerObj.getGuiMode();
431:
432: switch (mode) {
433: case SQLCondition.GUIMODE_SQLCODE:
434: rightTextPanel.setDirty(true);
435: rightPanel.setSelectedComponent(rightTextPanel);
436: rightGraphPanel.setModifiable(false);
437: break;
438: case SQLCondition.GUIMODE_GRAPHICAL:
439: rightGraphPanel.setDirty(true);
440: rightPanel.setSelectedComponent(rightGraphPanel);
441: rightTextPanel.setModifiable(false);
442: break;
443:
444: }
445:
446: reLoad = false;
447: }
448: }
|