/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.transformation.ui.editors.sqleditor; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EventObject; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IUndoManager; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ExtendedModifyEvent; import org.eclipse.swt.custom.ExtendedModifyListener; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.VerifyKeyListener; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.events.VerifyEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.texteditor.DefaultRangeIndicator; import org.teiid.core.designer.PluginUtil; import org.teiid.core.designer.event.EventObjectListener; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.query.QueryValidationResult; import org.teiid.designer.core.query.QueryValidator; import org.teiid.designer.query.IQueryService; import org.teiid.designer.query.sql.ISQLConstants; import org.teiid.designer.query.sql.ISQLStringVisitor; import org.teiid.designer.query.sql.lang.ICommand; import org.teiid.designer.query.sql.lang.ICriteria; import org.teiid.designer.query.sql.lang.IExpression; import org.teiid.designer.query.sql.lang.ILanguageObject; import org.teiid.designer.query.sql.lang.ISelect; import org.teiid.designer.query.sql.lang.ISetQuery; import org.teiid.designer.query.sql.lang.ISubqueryContainer; import org.teiid.designer.query.sql.symbol.IFunction; import org.teiid.designer.transformation.ui.Messages; import org.teiid.designer.transformation.ui.UiConstants; import org.teiid.designer.transformation.ui.UiPlugin; import org.teiid.designer.transformation.ui.actions.CreateFunctionAction; import org.teiid.designer.transformation.ui.builder.CriteriaBuilder; import org.teiid.designer.transformation.ui.builder.ExpressionBuilder; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.DownFont; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.ExpandSelect; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.ExportToFile; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.ImportFromFile; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.LaunchCreateFunction; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.LaunchCriteriaBuilder; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.LaunchExpressionBuilder; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.ToggleMessage; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.ToggleOptimizer; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.UpFont; import org.teiid.designer.transformation.ui.editors.sqleditor.actions.Validate; import org.teiid.designer.transformation.ui.wizards.sqlbuilder.SQLTemplateDialog; import org.teiid.designer.transformation.util.SqlStringUtil; import org.teiid.designer.transformation.util.TransformationHelper; import org.teiid.designer.ui.common.graphics.ColorManager; import org.teiid.designer.ui.common.text.ScaledFontManager; import org.teiid.designer.ui.common.text.StyledTextEditor; import org.teiid.designer.ui.common.text.TextFontManager; import org.teiid.designer.ui.common.util.UiUtil; import org.teiid.query.ui.builder.util.ElementViewerFactory; import org.teiid.query.ui.sqleditor.component.AliasSymbolDisplayNode; import org.teiid.query.ui.sqleditor.component.DeleteDisplayNode; import org.teiid.query.ui.sqleditor.component.DisplayNode; import org.teiid.query.ui.sqleditor.component.DisplayNodeConstants; import org.teiid.query.ui.sqleditor.component.DisplayNodeUtils; import org.teiid.query.ui.sqleditor.component.FunctionDisplayNode; import org.teiid.query.ui.sqleditor.component.GroupSymbolFinder; import org.teiid.query.ui.sqleditor.component.QueryDisplayComponent; import org.teiid.query.ui.sqleditor.component.QueryDisplayNode; import org.teiid.query.ui.sqleditor.component.SelectDisplayNode; import org.teiid.query.ui.sqleditor.component.SetQueryDisplayNode; import org.teiid.query.ui.sqleditor.component.SqlIndexLocator; import org.teiid.query.ui.sqleditor.component.UpdateDisplayNode; import org.teiid.query.ui.sqleditor.component.WhereDisplayNode; /** * @since 8.0 */ public class SqlEditorPanel extends SashForm implements UiConstants, DisplayNodeConstants, SelectionListener, ISelectionChangedListener, IPropertyChangeListener, KeyListener, MouseListener, IMenuListener { /** Changes Pending Message */ private static final String QUERY_CHANGES_PENDING_MESSAGE = Util.getString("SqlEditorPanel.changesPendingMsg"); //$NON-NLS-1$ private static final String IMPORT_PROBLEM = "SqlEditorPanel.importProb"; //$NON-NLS-1$ private static final String EXPORT_PROBLEM = "SqlEditorPanel.exportProb"; //$NON-NLS-1$ private static final String EXPORT_SQL_DIALOG_TITLE = "SqlEditorPanel.exportSqlDialog.title"; //$NON-NLS-1$ private static final String IMPORT_SQL_DIALOG_TITLE = "SqlEditorPanel.importSqlDialog.title"; //$NON-NLS-1$ private static final String IMPORT_SQL_PROBLEM_DIALOG_TITLE = "SqlEditorPanel.importSqlProblemDialog.title"; //$NON-NLS-1$ private static final String EXPORT_DEFAULT_FILENAME = "SqlEditorPanel.exportDefaultFile.text"; //$NON-NLS-1$ private static final String EXPORT_DEFAULT_FILEEXT = "SqlEditorPanel.exportDefaultExtension.text"; //$NON-NLS-1$ private static final String MONITOR_VALIDATING_SQL = "SqlEditorPanel.validatingSQL"; //$NON-NLS-1$ public static final String ACTION_ID_VALIDATE = "Validate"; //$NON-NLS-1$ // Validate validateAction public static final String ACTION_ID_LAUNCH_CRITERIA_BUILDER = "LaunchCriteriaBuilder"; //$NON-NLS-1$ // LaunchCriteriaBuilder launchCriteriaBuilderAction; public static final String ACTION_ID_LAUNCH_EXPRESSION_BUILDER = "LaunchExpressionBuilder"; //$NON-NLS-1$ // LaunchExpressionBuilder launchExpressionBuilderAction; public static final String ACTION_ID_LAUNCH_CREATE_FUNCTION = "LaunchCreateFunction"; //$NON-NLS-1$ public static final String ACTION_ID_EXPAND_SELECT = "ExpandSelect"; //$NON-NLS-1$ // ExpandSelect expandSelectAction; public static final String ACTION_ID_TOGGLE_MESSAGE = "ToggleMessage"; //$NON-NLS-1$ // ToggleMessage toggleMessageAction; public static final String ACTION_ID_TOGGLE_OPTIMIZER = "ToggleOptimizer"; //$NON-NLS-1$ // ToggleOptimizer toggleOptimizerAction; public static final String ACTION_ID_UP_FONT = "UpFont"; //$NON-NLS-1$ // UpFont upFontAction; public static final String ACTION_ID_DOWN_FONT = "DownFont"; //$NON-NLS-1$ // DownFont downFontAction; public static final String ACTION_ID_IMPORT_FROM_FILE = "ImportFromFile"; //$NON-NLS-1$ // ImportFromFile importFromFileAction; public static final String ACTION_ID_EXPORT_TO_FILE = "ExportToFile"; //$NON-NLS-1$ // ExportToFile exportToFileAction; public static final String APPLY_TEMPLATE_ACTION_TEXT = "SqlEditorPanel.applyTemplateActionText"; //$NON-NLS-1$ public static final String APPLY_TEMPLATE_ACTION_TOOLTIP = "SqlEditorPanel.applyTemplateActionTooltip"; //$NON-NLS-1$ public static final String CREATE_FUNCTION_ACTION_TEXT = "SqlEditorPanel.createFunctionActionText"; //$NON-NLS-1$ public static final String CREATE_FUNCTION_ACTION_TOOLTIP = "SqlEditorPanel.createFunctionActionTooltip"; //$NON-NLS-1$ public static final String[] DEFAULT_INCLUDED_ACTIONS = new String[] {ACTION_ID_VALIDATE, ACTION_ID_LAUNCH_CRITERIA_BUILDER, ACTION_ID_LAUNCH_EXPRESSION_BUILDER, ACTION_ID_EXPAND_SELECT, ACTION_ID_TOGGLE_MESSAGE, ACTION_ID_TOGGLE_OPTIMIZER, ACTION_ID_UP_FONT, ACTION_ID_DOWN_FONT, ACTION_ID_IMPORT_FROM_FILE, ACTION_ID_EXPORT_TO_FILE}; private ColorManager colorManager; private Color currentBkgdColor; private Color widgetBkgdColor; private IVerticalRuler verticalRuler; SqlTextViewer sqlTextViewer; private StyledTextEditor textEditor; // private SqlFormattingStrategy formattingStrategy; IDocument sqlDocument; private boolean messageShowing = true; StyledTextEditor messageArea; QueryDisplayComponent queryDisplayComponent; ViewForm sqlViewForm; // ------------------------------------------------------------------------------------------------------------------- // DEFECT 23230 // We need to cache the panelSqlText here to maintain the last setText() value // ------------------------------------------------------------------------------------------------------------------- private String panelSqlText = null; boolean validateSelected = false; boolean hasPendingChanges = false; boolean isCompleteRefresh = false; private boolean hasUserError = false; private boolean isEditable = true; private TextFontManager tfmManager; private boolean selectExpansionEnabled = true; /** select Drop Enabled status */ private boolean selectDropsEnabled = true; private int caretOffset = -1; private int caretXPosition = 0; private int caretYPosition = 0; // Actions private List<IAction> actionList = null; Validate validateAction; LaunchCriteriaBuilder launchCriteriaBuilderAction; LaunchExpressionBuilder launchExpressionBuilderAction; LaunchCreateFunction launchCreateFunctionAction; ExpandSelect expandSelectAction; ToggleMessage toggleMessageAction; ToggleOptimizer toggleOptimizerAction; UpFont upFontAction; DownFont downFontAction; ImportFromFile importFromFileAction; ExportToFile exportToFileAction; private Action applyTemplateAction; private Action createFunctionAction; List includedActionsList; /** The width of the vertical ruler. */ private Object eventSource; /** The width of the vertical ruler. */ protected final static int VERTICAL_RULER_WIDTH = 0; /** The editor's text listener. */ // private ITextListener textListener= new TextListener(); /** List of listeners registered for this panels events */ private List eventListeners; /** List of listeners registered for this panels internal events */ private List internalEventListeners; private Collection externalBuilderGroups = null; String savedSql = BLANK; String currentMessage = BLANK; private List setQueryStates; private int panelType = UiConstants.SQLPanels.SELECT; /** * Constructor. * * @param parent Parent of this control */ public SqlEditorPanel( Composite parent, QueryValidator queryValidator, int queryType ) { super(parent, SWT.VERTICAL); init(queryValidator, queryType); includedActionsList = getDefaultActionList(); } /** * Constructor. * * @param parent Parent of this control */ public SqlEditorPanel( Composite parent, QueryValidator queryValidator, int queryType, List actionsList ) { super(parent, SWT.VERTICAL); init(queryValidator, queryType); this.includedActionsList = actionsList; } /** * Initialize the panel. */ private void init( QueryValidator queryValidator, int queryType ) { // this.formattingStrategy = // new SqlFormattingStrategy(); queryDisplayComponent = new QueryDisplayComponent(queryValidator, queryType); colorManager = new ColorManager(); currentBkgdColor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); widgetBkgdColor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); // ... Do NOT create a vertical ruler at this time (4.0, beta1...GA?) // This is used to carry line by line marks, like the error and warning decorations // used in the eclipse java ide (jdt). We will not have such features for the // forseeable future and until then this space is wasted (see also Defect 10366) // verticalRuler= new VerticalRuler(VERTICAL_RULER_WIDTH); // add message area to ViewForm to get Eclipse view look sqlViewForm = new ViewForm(this, SWT.BORDER); int styles = SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.FULL_SELECTION; sqlTextViewer = new SqlTextViewer(sqlViewForm, verticalRuler, styles, colorManager); sqlViewForm.setContent(sqlTextViewer.getControl()); sqlTextViewer.getTextWidget().addVerifyKeyListener(new VerifyKeyListener() { @Override public void verifyKey( VerifyEvent event ) { if ((event.stateMask == SWT.CTRL && event.character == 127) || (event.stateMask == SWT.CTRL && event.character == ' ')) { event.doit = false; sqlTextViewer.showAssistance(); } } }); sqlTextViewer.getTextWidget().addMouseListener(new MouseListener() { @Override public void mouseDoubleClick( MouseEvent event ) { sqlTextViewer.handleDoubleClick(); } @Override public void mouseUp( MouseEvent event ) { } @Override public void mouseDown( MouseEvent event ) { captureCaretInfo(); } }); sqlTextViewer.getTextWidget().addExtendedModifyListener(new ExtendedModifyListener() { // This method is invoked every time the text changes @Override public void modifyText( ExtendedModifyEvent event ) { fireEditorInternalEvent(SqlEditorInternalEvent.TEXT_CHANGED); } }); this.textEditor = new StyledTextEditor(this.sqlTextViewer); this.textEditor.setAlwaysAllowPaste(true); this.textEditor.addMenuListener(this); // sqlDocument.set("SELECT * FROM TABLE"); sqlDocument = textEditor.getDocument(); sqlTextViewer.setEditable(true); isEditable = true; // Initialize optimization IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); boolean optimizationOn = prefStore.getBoolean(org.teiid.query.ui.UiConstants.Prefs.SQL_OPTIMIZATION_ON); queryDisplayComponent.setOptimizerOn(optimizationOn); sqlTextViewer.setRangeIndicator(new DefaultRangeIndicator()); // Set overall grid layout GridLayout gridLayout = new GridLayout(); this.setLayout(gridLayout); gridLayout.numColumns = 1; GridData gridData = new GridData(GridData.FILL_BOTH); this.setLayoutData(gridData); gridData.horizontalAlignment = GridData.FILL; gridData.verticalAlignment = GridData.FILL; // textArea.addExtendedModifyListener(modifyListener); gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; textEditor.setLayoutData(gridData); // add message area to ViewForm to get Eclipse view look ViewForm msgViewForm = new ViewForm(this, SWT.BORDER); int messageAreaStyle = SWT.READ_ONLY | SWT.V_SCROLL | SWT.WRAP; messageArea = StyledTextEditor.createReadOnlyEditor(msgViewForm, messageAreaStyle); messageArea.setLayoutData(gridData); messageArea.setBackground(widgetBkgdColor); msgViewForm.setContent(messageArea.getTextWidget()); sqlTextViewer.getTextWidget().addSelectionListener(this); sqlTextViewer.addSelectionChangedListener(this); sqlTextViewer.getTextWidget().addKeyListener(this); sqlTextViewer.getTextWidget().addMouseListener(this); int[] wts = {4, 1}; setWeights(wts); showMessageArea(false); prefStore.addPropertyChangeListener(this); // Add Document Listener to for notification of text changes sqlDocument.addDocumentListener(new DocumentChangeListener()); } @Override public void menuAboutToShow( IMenuManager manager ) { manager.add(new Separator()); this.applyTemplateAction = new Action(null) { @Override public void run() { handleApplyTemplate(); } }; this.applyTemplateAction.setToolTipText(Util.getString(APPLY_TEMPLATE_ACTION_TOOLTIP)); this.applyTemplateAction.setText(Util.getString(APPLY_TEMPLATE_ACTION_TEXT)); this.applyTemplateAction.setEnabled(true); manager.add(this.applyTemplateAction); this.createFunctionAction = new Action(null) { @Override public void run() { launchCreateFunction(); } }; this.createFunctionAction.setToolTipText(Util.getString(CREATE_FUNCTION_ACTION_TOOLTIP)); this.createFunctionAction.setText(Util.getString(CREATE_FUNCTION_ACTION_TEXT)); this.createFunctionAction.setEnabled(true); manager.add(this.createFunctionAction); } private void handleApplyTemplate() { SQLTemplateDialog templateDialog = new SQLTemplateDialog(UiUtil.getWorkbenchShellOnlyIfUiThread(), SQLTemplateDialog.ALL_TEMPLATES); if (templateDialog.open() == Window.OK) { boolean okToInsertOrReplace = true; if( templateDialog.getInsertOption() == ISQLConstants.INSERT_OPTIONS.REPLACE_ALL ) { // make sure user want to replace all okToInsertOrReplace = MessageDialog.openConfirm(templateDialog.getShell(), Messages.confirmSqlReplaceDialogTitle, Messages.confirmSqlReplaceDialogMessage); } if( okToInsertOrReplace ) { int offset = getCaretOffset(); // Insert at the offset String currentSQL = getText(); String newSql = SqlStringUtil.insertSql( currentSQL, templateDialog.getSQL(), templateDialog.getInsertOption(), offset); setText(newSql, templateDialog ); } } } /** * Clears the undo/redo history of the SQL text editor. * * @since 5.5.3 */ public void resetUndoRedoHistory() { this.textEditor.resetUndoRedoHistory(); } /** * handle preference change. This only responds to change in formatting preference. */ @Override public void propertyChange( PropertyChangeEvent e ) { String propStr = e.getProperty(); if (propStr != null && (propStr.equals(org.teiid.query.ui.UiConstants.Prefs.START_CLAUSES_ON_NEW_LINE) || propStr.equals(org.teiid.query.ui.UiConstants.Prefs.INDENT_CLAUSE_CONTENT))) { if (!this.isDisposed() && this.isVisible()) { setText(getText()); } } } public void setQueryValidator( QueryValidator validator ) { this.queryDisplayComponent.setQueryValidator(validator); } /** * get the SQL Text from the panel * * @return the SQL text from the panel */ public String getText() { return sqlDocument.get(); } void setTextInTransaction( final String proposedSqlText, final Object source, final boolean doResolveAndValidate, final QueryValidationResult result, final IProgressMonitor monitor ) { boolean requiredStart = false; boolean succeeded = false; // System.out.println(" SqlEditorPanel.setTextInTxn(): hasPendingChanges = " + hasPendingChanges + " CURRENT SQL = " + // panelSqlText); try { requiredStart = ModelerCore.startTxn(true, false, "Setting Sql Text", source); //$NON-NLS-1$ // -------------------------------------------------------- this.eventSource = source; // ------------------------------------------------------------------------------------------------------------------- // DEFECT 23230 // Added String check here to prevent unnecessary validation if SQL doesn't change. // ------------------------------------------------------------------------------------------------------------------- boolean setSqlText = hasPendingChanges; // Have to check for hasPendingChanges because their may have been changes in the "Hidden" display nodes. if (!setSqlText) { setSqlText = TransformationHelper.stringsDifferent(panelSqlText, proposedSqlText); } // System.out.println(" --------------- SQL Changed = " + setSqlText + " SQL = " + proposedSqlText); if (setSqlText) { panelSqlText = proposedSqlText; //System.out.println(" >> SEP.setText() Called: calling queryDisplayComponent.setText() SQL = " + panelSqlText); TransformationHelper.setSqlString( queryDisplayComponent.getMappingRoot(), panelSqlText, queryDisplayComponent.getQueryType(), false, this); queryDisplayComponent.setText(panelSqlText, doResolveAndValidate, result, monitor); // Refresh the EditorPanel, using the queryDisplayComponent refreshWithDisplayComponent(); monitor.worked(10); // Fire Editor State to rest of Editor // DO NOT fire EditorEvent // fireEditorInternalEvent(SqlEditorInternalEvent.TEXT_RESET); // After setting text, set eventSource to this. this.eventSource = this; } succeeded = true; } catch (Exception ex) { UiConstants.Util.log(IStatus.ERROR, ex, ex.getClass().getName() + ":" + this.getClass().getName() + ".setTextInTransaction()"); //$NON-NLS-1$ //$NON-NLS-2$ } finally { if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } /** * Sets the SQL Statement on the Panel * * @param SQLString the SQL String to set on the panel */ public void setText( final String sql, final Object source, final boolean doResolveAndValidate, final QueryValidationResult theResult ) { if (doResolveAndValidate) { final IRunnableWithProgress op = new IRunnableWithProgress() { @Override public void run( final IProgressMonitor theMonitor ) { theMonitor.beginTask(MONITOR_VALIDATING_SQL, 100); theMonitor.worked(20); setTextInTransaction(sql, source, doResolveAndValidate, theResult, theMonitor); theMonitor.done(); } }; try { new ProgressMonitorDialog(Display.getCurrent().getActiveShell()).run(false, true, op); } catch (InterruptedException e) { } catch (InvocationTargetException e) { UiConstants.Util.log(e.getTargetException()); } catch (Exception e) { UiConstants.Util.log(e.getMessage()); } } else { setTextInTransaction(sql, source, doResolveAndValidate, theResult, new NullProgressMonitor()); } } public void clear() { savedSql = BLANK; panelSqlText = null; queryDisplayComponent.reset(); refreshWithDisplayComponent(); } /* * Private method to set sql string text. Only used by methods internal to SqlEditorPanel * Assumes that validation will be run on new sql string */ private void setText( final String sql, Object source ) { setText(sql, source, true, null); } /** * Sets the SQL Statement on the Panel * * @param SQLString the SQL String to set on the panel */ public void setText( final String sql ) { this.eventSource = this; // If null sql, use blank string String theSql = sql; if (sql == null) theSql = BLANK; queryDisplayComponent.setText(theSql, true, null); // Refresh the EditorPanel, using the queryDisplayComponent refreshWithDisplayComponent(); } /** * Method executed to Validate the current SQL text. */ public void validate() { String panelText = getText(); // Set validate Selected validateSelected = true; // Reset Text on Panel to reformat setText(panelText, this); } public boolean threadIsNotDisplayThread() { return (this.getDisplay() != null && Thread.currentThread() != this.getDisplay().getThread()); } /** * Refreshes the Query JTextPane with the contents of the queryDisplayComponent */ private void refreshWithDisplayComponent() { hasPendingChanges = false; isCompleteRefresh = true; // point the font manager to the current editor's text viewer if (threadIsNotDisplayThread()) { this.getDisplay().asyncExec(new Runnable() { @Override public void run() { setMessage(queryDisplayComponent); // Set the SQL Text displayed. sqlDocument.set(queryDisplayComponent.toDisplayString()); setQueryTextBackground(); } }); } else { setMessage(queryDisplayComponent); // Set the SQL Text displayed. sqlDocument.set(queryDisplayComponent.toDisplayString()); setQueryTextBackground(); } } /** * Fire a SqlEditorEvent to the registered listeners, based on the state of SQL displayed * (CHANGES_PENDING,CHANGED,PARSABLE,RESOLVABLE,VALIDATABLE, CARET_CHANGED). */ void fireEditorEvent() { // Event source is this panel if null if (eventSource == null) { eventSource = this; } boolean isParsable = queryDisplayComponent.isParsable(); boolean isResolvable = queryDisplayComponent.isResolvable(); boolean isValidatable = queryDisplayComponent.isValidatable(); SqlEditorEvent event = null; // Has Pending Changes if (hasPendingChanges) { event = new SqlEditorEvent(eventSource, SqlEditorEvent.CHANGES_PENDING); // Sql changed but not parsable } else if (!isParsable) { event = new SqlEditorEvent(eventSource, getText(), SqlEditorEvent.CHANGED); // Sql changed, parsable but not resolvable } else if (!isResolvable) { event = new SqlEditorEvent(eventSource, getCommand(), getText(), SqlEditorEvent.PARSABLE); // Sql changed, resolvable but not validatable } else if (!isValidatable) { // fire the event event = new SqlEditorEvent(eventSource, getCommand(), getText(), SqlEditorEvent.RESOLVABLE); // Sql changed, validatable } else { // fire the event event = new SqlEditorEvent(eventSource, getCommand(), getText(), SqlEditorEvent.VALIDATABLE); } notifyEventListeners(event); } /** * Fire a SqlEditorEvent to the registered listeners indicating CARET_CHANGED on displayed SQL * * @since 4.2 */ private void notifyCaretChanged() { notifyEventListeners(new SqlEditorEvent(this, SqlEditorEvent.CARET_CHANGED)); } /** * Fire a SqlEditorInternalEvent to the registered listeners, based on the eventType * (SqlEditorInternalEvent.TEXT_RESET,TEXT_INSERT,TEXT_REMOVE,READONLY_CHANGED,CARET_CHANGED * * @param eventType the type of internal event to fire */ protected void fireEditorInternalEvent( int eventType ) { SqlEditorInternalEvent event = new SqlEditorInternalEvent(this, eventType); notifyInternalEventListeners(event); } /** * This method will register the listener for all SqlEditorEvents * * @param listener the listener to be registered */ public void addEventListener( EventObjectListener listener ) { if (eventListeners == null) { eventListeners = new ArrayList(); } eventListeners.add(listener); } /** * This method will un-register the listener for all SqlEditorEvents * * @param listener the listener to be un-registered */ public void removeEventListener( EventObjectListener listener ) { if (eventListeners != null) { eventListeners.remove(listener); } } /** * This method will notify the registered listeners of a SqlEditorEvent */ private void notifyEventListeners( EventObject event ) { if (eventListeners != null) { Iterator iterator = eventListeners.iterator(); while (iterator.hasNext()) { EventObjectListener listener = (EventObjectListener)iterator.next(); if (listener != null) { listener.processEvent(event); } } } } /** * This method will register the listener for all SqlEditorInternalEvents * * @param listener the listener to be registered */ public void addInternalEventListener( EventObjectListener listener ) { if (internalEventListeners == null) { internalEventListeners = new ArrayList(); } internalEventListeners.add(listener); } /** * This method will un-register the listener for all SqlEditorEvents * * @param listener the listener to be un-registered */ public void removeInternalEventListener( EventObjectListener listener ) { if (internalEventListeners != null) { internalEventListeners.remove(listener); } } /** * This method will notify the registered listeners of a SqlEditorEvent */ private void notifyInternalEventListeners( EventObject event ) { if (internalEventListeners != null) { Iterator iterator = internalEventListeners.iterator(); while (iterator.hasNext()) { EventObjectListener listener = (EventObjectListener)iterator.next(); if (listener != null) { listener.processEvent(event); } } } } /** * Get the Command for the currently displayed SQL * * @return the command, null if the query is not both parseable and resolvable */ public ICommand getCommand() { return queryDisplayComponent.getCommand(); } public void showMessageArea( final boolean show ) { if (!isDisposed()) { if (show != messageShowing) { if (threadIsNotDisplayThread()) { this.getDisplay().asyncExec(new Runnable() { @Override public void run() { if (show) { setMaximizedControl(null); setMessage(currentMessage); } else { setMaximizedControl(sqlViewForm); } } }); } else { if (show) { setMaximizedControl(null); setMessage(currentMessage); } else { setMaximizedControl(sqlViewForm); } } messageShowing = !messageShowing; } fireEditorInternalEvent(SqlEditorInternalEvent.MESSAGE_VISIBILITY_CHANGED); } } public boolean isMessageAreaVisible() { return messageShowing; } /** * Set the Text in the Message for a QueryDisplayComponent. * * @param displayComponent the QueryDisplayComponent */ void setMessage( QueryDisplayComponent displayComponent ) { setMessage(queryDisplayComponent.getStatusMessage()); } /** * Set the Text in the Message for a QueryDisplayComponent. * * @param displayComponent the QueryDisplayComponent */ public void setMessage( String messageText ) { currentMessage = messageText; if (!messageArea.isDisposed()) { // point the font manager to the current editor's text viewer if (threadIsNotDisplayThread()) { this.getDisplay().asyncExec(new Runnable() { @Override public void run() { if (currentMessage != null) { messageArea.setText(currentMessage); } else { messageArea.setText(""); //$NON-NLS-1$ } } }); } else { if (currentMessage != null) { messageArea.setText(currentMessage); } else { messageArea.setText(""); //$NON-NLS-1$ } } } } /** * Set enabled status of drops into a SELECT on the SQLTextPanel. Default is 'true' * * @param status 'true' if drops are enabled, 'false' if not. */ public void setSelectDropsEnabled( boolean status ) { selectDropsEnabled = status; } /** * Set enabled status of expansion of the SELECT on the SQLTextPanel * * @param status 'true' if expansion is enabled, 'false' if not. */ public void setSelectExpansionEnabled( boolean status ) { selectExpansionEnabled = status; } /** * Set the SetQuery reconciled states - whether each part of the SetQuery is reconciled to the target or not. Used for editor * panel highlighting. * * @param reconciledStates the list of boolean states */ public void setSetQueryReconciledStates( List reconciledStates ) { setQueryStates = reconciledStates; setTextViewerBackgroundColors(getCaretOffset()); } /** * Method to set background color when the query is not parsable or resolvable */ void setQueryTextBackground() { StyledText sqlTextArea = sqlTextViewer.getTextWidget(); if (sqlTextArea != null) { Color bkgdColor = widgetBkgdColor; if (hasPendingChanges || hasUserError) { bkgdColor = colorManager.getColor(ColorManager.BACKGROUND_INVALID); } else { if (isEditable()) { if (queryDisplayComponent.isValidatable()) { bkgdColor = colorManager.getColor(ColorManager.BACKGROUND_VALID); } else { bkgdColor = colorManager.getColor(ColorManager.BACKGROUND_INVALID); } } } setSqlTextAreaBackgroundColor(bkgdColor); // Need to set the Line Background color to the same here because it may have been // Set in the OTHER method StyledText styledText = this.sqlTextViewer.getTextWidget(); int textLength = styledText.getText().length(); // get start and end lines for entire text int wholeStartLine = 0; int wholeEndLine = styledText.getLineAtOffset(textLength); int nAllLines = wholeEndLine - wholeStartLine + 1; styledText.setLineBackground(wholeStartLine, nAllLines, bkgdColor); } } private void setSqlTextAreaBackgroundColor( Color bkgdColor ) { StyledText sqlTextArea = sqlTextViewer.getTextWidget(); if (sqlTextArea != null) { if (!currentBkgdColor.getRGB().equals(bkgdColor.getRGB())) { currentBkgdColor = bkgdColor; sqlTextArea.setBackground(bkgdColor); } } } /** * Sets whether the displayed query can be edited * * @param status true if the query can be edited, false if not */ public void setEditable( final boolean status ) { // point the font manager to the current editor's text viewer isEditable = status; if (threadIsNotDisplayThread()) { this.getDisplay().asyncExec(new Runnable() { @Override public void run() { sqlTextViewer.setEditable(status); setQueryTextBackground(); } }); } else { sqlTextViewer.setEditable(status); setQueryTextBackground(); } fireEditorInternalEvent(SqlEditorInternalEvent.READONLY_CHANGED); } /** * Set any external groups that the builder will need for it's treeView groups. Example of this is when the transformation * target is a MappingClass. Then, the builders need access to the InputSet groups (nested under MappingClass). This is * different than 3.1 because the InputSets are no longer in the Query FROM clause. * * @param groups the collection of external groups to add to the builder trees. */ public void setExternalBuilderGroups( Collection groups ) { this.externalBuilderGroups = groups; } /** * Turn the SQL optimization on or off. * * @param state the optimizer state, 'true' = on, 'false' = off */ public void setOptimizerOn( boolean status ) { // Sets the optimization preference - the panel in turn responds to preference change IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); boolean currentValue = prefStore.getBoolean(org.teiid.query.ui.UiConstants.Prefs.SQL_OPTIMIZATION_ON); if (status != currentValue) { prefStore.setValue(org.teiid.query.ui.UiConstants.Prefs.SQL_OPTIMIZATION_ON, status); } boolean isOn = isOptimizerOn(); // If desired state is opposite of current state, set on queryDisplayComponent if (status != isOn) { queryDisplayComponent.setOptimizerOn(status); if (!hasPendingChanges()) { refreshWithDisplayComponent(); } // Fire Editor State to rest of Editor fireEditorInternalEvent(SqlEditorInternalEvent.OPTIMIZER_STATE_CHANGED); } } /** * Determine if SQL optimization is on. * * @return the optimizer on state - 'true' is on, 'false' is off */ public boolean isOptimizerOn() { return queryDisplayComponent.isOptimizerOn(); } /** * Determine if the optimizer can be used for the current SQL. * * @return 'true' if the optimizer can be used, 'false' is not. */ public boolean canOptimize() { return queryDisplayComponent.canOptimize(); } /** * Determine whether the displayed query can be edited * * @return true if the query can be edited, false if not */ public boolean isEditable() { return isEditable; } /** * Tests whether the editor panel contains a valid SQL statement. Parsable means that the statement is valid SQL. * * @return the boolean status of the SQL statement */ public boolean isParsable() { if (hasPendingChanges) { return false; } return queryDisplayComponent.isParsable(); } /** * Tests whether the editor panel contains a resolvable sql statment. * * @return the boolean status of the SQL statement */ public boolean isResolvable() { if (hasPendingChanges) { return false; } return queryDisplayComponent.isResolvable(); } /** * Tests whether the editor panel contains a valid sql statment. Valid in this case means that it is parsable, resolvable and * validatable SQL. * * @return the boolean status of the SQL statement */ public boolean isValid() { if (hasPendingChanges) { return false; } return queryDisplayComponent.isValidatable(); } /** * Tests whether the editor panel contains the default SQL statement. * * @return the boolean status of the SQL statement */ public boolean isDefaultQuery() { return queryDisplayComponent.isDefaultQuery(); } /** * Method to set whether the editorPanel has errors * * @param status true if theres an error, false if not */ public void setHasError( boolean status ) { hasUserError = status; // Set error background setQueryTextBackground(); } /** * This method determines whether the Expression Builder Dialog can be launched at the current caret position. * * @return 'true' if the ExpressionBuilder can be launched, 'false' if not. */ public boolean canUseExpressionBuilder() { // Cannot Use ExpressionBuilder under these conditions (may change) if (!isEditable() || !isParsable()) { return false; } // Can use ExpressionBuilder if currently in an expression or its valid to insert new int caretIndex = getCorrectedCaretOffset(); if (isIndexWithin(caretIndex, EXPRESSION) || isInsertAllowed(caretIndex, EXPRESSION)) { return true; } return false; } /** * This method determines whether the Create Function Dialog can be launched at the current caret position. * * @return 'true' if the ExpressionBuilder can be launched, 'false' if not. */ public boolean canCreateFunction() { // Cannot Use ExpressionBuilder under these conditions (may change) if (!isEditable() || !isParsable()) { return false; } // Can use ExpressionBuilder if currently in an expression or its valid to insert new int caretIndex = getCorrectedCaretOffset(); if (isIndexWithin(caretIndex, EXPRESSION)) { return true; } return false; } /** * This method determines whether the Criteria Builder Dialog can be launched at the current caret position. * * @return 'true' if the CriteriaBuilder can be launched, 'false' if not. */ public boolean canUseCriteriaBuilder() { // Cannot Use CriteriaBuilder under these conditions (may change) if (!isEditable() || !isParsable()) { return false; } // Can use CriteriaBuilder if currently in a criteria, if the current command has // a WHERE clause, or its valid to insert new int caretIndex = getCorrectedCaretOffset(); List displayNodes = queryDisplayComponent.getDisplayNodeList(); DisplayNode criteriaNode = DisplayNodeUtils.getNodeTypeAtIndex(displayNodes, caretIndex, CRITERIA); if (criteriaNode != null || commandHasEditableCriteriaClause(caretIndex) || isInsertAllowed(caretIndex, CRITERIA)) { return true; } return false; } private ExpressionBuilder getExpressionBuilder() { Shell shell = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); ExpressionBuilder expressionBuilder = new ExpressionBuilder(shell); expressionBuilder.create(); return expressionBuilder; } private CriteriaBuilder getCriteriaBuilder() { Shell shell = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); CriteriaBuilder criteriaBuilder = new CriteriaBuilder(shell); criteriaBuilder.create(); return criteriaBuilder; } /** * This method launches the Expression Builder Dialog. If the current SQLTextPanel caret is currently within an Expression, * the Expression Builder is launched with the supplied expression. The supplied expression is replaced with the modified * expression when the function builder is dismissed. If the caret is not within an expression, the Function Builder is * launched without an expression. The resulting expression is inserted into the editor panel. */ public void showExpressionBuilder() { int index = getCorrectedCaretOffset(); // ----------------------------------------------------------- // Get Expression at the index // ----------------------------------------------------------- DisplayNode expressionNode = getExpressionAtIndex(index); int startIndex = 0; int endIndex = 0; boolean replaceMode = false; // ------------------------------------------------------------------------------ // If the index is within an expression, replace the expression, else insert it // ------------------------------------------------------------------------------ if (expressionNode != null) { startIndex = expressionNode.getStartIndex(); endIndex = expressionNode.getEndIndex(); replaceMode = true; } // load the Groups that are in context into the ElementViewerFactory List groups = getGroupsForBuilderTree(true); while (groups.contains(null) && groups.size() > 0) { groups.remove(null); } ElementViewerFactory.setViewerInput(groups); // ---------------------------------------------------------------------------- // If the caret is within an expression, construct panel with the expression // Otherwise, construct panel for insert // ---------------------------------------------------------------------------- ExpressionBuilder builder = getExpressionBuilder(); // launch Epression Builder with the selected language object or with // null to start off with undefined language object builder.setLanguageObject((replaceMode) ? (IExpression)expressionNode.getLanguageObject() : null); // ------------------------------------------------------------------------- // Display the Dialog // ------------------------------------------------------------------------- int status = builder.open(); // ------------------------------------------------------------------------- // Insert or Replace when Dialog is OK'd, do nothing if cancelled // ------------------------------------------------------------------------- if (status == Window.OK) { ILanguageObject langObj = builder.getLanguageObject(); IQueryService queryService = ModelerCore.getTeiidQueryService(); ISQLStringVisitor visitor = queryService.getSQLStringVisitor(); String langString = visitor.returnSQLString(langObj); // ------------------ // Replace Mode // ------------------ if (replaceMode) { StringBuffer currentSQL = new StringBuffer(queryDisplayComponent.toString()); currentSQL.replace(startIndex, endIndex + 1, langString); setText(currentSQL.toString(), this); // ------------------ // Insert Mode // ------------------ } else { // Handle SELECT * (special case - it must be expanded first) if (queryDisplayComponent.isIndexWithin(index, DisplayNodeConstants.SELECT)) { // Get Select clause DisplayNode DisplayNode clauseNode = queryDisplayComponent.getQueryClauseAtIndex(index); ILanguageObject selectObj; try { selectObj = clauseNode.getLanguageObject(); if (selectObj != null && selectObj instanceof ISelect) { // Check whether this is a "SELECT *" if (((ISelect)selectObj).isStar()) { // First check if the cursor is after the * boolean isAtClauseEnd = DisplayNodeUtils.isIndexAtClauseEnd(clauseNode, index); // Expand the Select queryDisplayComponent.expandSelect(index); // If the cursor was after the *, adjust the cursor index after expansion if (isAtClauseEnd) { DisplayNode newClauseNode = queryDisplayComponent.getQueryClauseAtIndex(index); index = newClauseNode.getEndIndex(); } } } } catch (NullPointerException npe) { UiPlugin.getDefault().getPluginUtil().log(IStatus.ERROR, npe, "Clause Node was null at index: " + index); //$NON-NLS-1$ UiPlugin.getDefault().getPluginUtil().log(IStatus.ERROR, npe, "Text was: " + getText()); //$NON-NLS-1$ } } // Get currently displayed SQL StringBuffer currentSQL = new StringBuffer(queryDisplayComponent.toString()); // Adjust the original index so that existing symbols arent broken int newIndex = adjustIndexForInsert(index); // Adjust the expression String to place commas before/after as appropriate String newExpressionString = adjustStringForInsert(langString, newIndex); // Insert Expression String at the index currentSQL.insert(newIndex, newExpressionString); // Reset the new SQL Text setText(currentSQL.toString(), this); } setCaretOffset(0); // Fires Editor Event based on state of queryDisplayComponent // fireEditorEvent(); } } /** * This method launches the Criteria Builder Dialog. If the current SQLTextPanel caret is currently within a criteria, the * Criteria Builder is launched with the supplied criteria. The supplied criteria is replaced with the modified criteria when * the builder is dismissed. If the caret is not within a criteria, the Criteria Builder is launched without a criteria. The * resulting criteria is inserted into the editor panel. * * @param index the index to launch the builder from. */ public void showCriteriaBuilder() { int index = getCorrectedCaretOffset(); // ----------------------------------------------------------- // Get Criteria at the index // ----------------------------------------------------------- DisplayNode criteriaNode = getCriteriaAtIndex(index, false); int startIndex = 0; int endIndex = 0; boolean replaceMode = false; // ------------------------------------------------------------------------- // If the index is within a criteria, replace the criteria, else insert it // ------------------------------------------------------------------------- if (criteriaNode != null) { startIndex = criteriaNode.getStartIndex(); endIndex = criteriaNode.getEndIndex(); replaceMode = true; } // load the Groups that are in context into the ElementViewerFactory List groups = getGroupsForBuilderTree(true); // this gets into loop if groups is empty while (groups.contains(null) && groups.size() > 0) { groups.remove(null); } ElementViewerFactory.setViewerInput(groups); // ------------------------------------------------------------------------- // If the caret is within a criteria, construct panel with the criteria // Otherwise, construct panel for insert // ------------------------------------------------------------------------- CriteriaBuilder builder = getCriteriaBuilder(); // launch Criteria Builder with the selected language object or with // null to start off with undefined language object builder.setLanguageObject((replaceMode) ? (ICriteria)criteriaNode.getLanguageObject() : null); // ------------------------------------------------------------------------- // Display the Dialog // ------------------------------------------------------------------------- int status = builder.open(); // ------------------------------------------------------------------------- // Insert or Replace when Dialog is OK'd, do nothing if cancelled // ------------------------------------------------------------------------- if (status == Window.OK) { ILanguageObject newCriteria = builder.getLanguageObject(); IQueryService queryService = ModelerCore.getTeiidQueryService(); ISQLStringVisitor visitor = queryService.getSQLStringVisitor(); String criteriaString = visitor.returnSQLString(newCriteria); // ------------------ // Replace Mode // ------------------ if (replaceMode) { StringBuffer currentSQL = new StringBuffer(queryDisplayComponent.toString()); currentSQL.replace(startIndex, endIndex + 1, criteriaString); setText(currentSQL.toString(), this); // -------------------------------------------------------------------------------- // Insert Mode - We should now only be inserting when there is not a WHERE clause // -------------------------------------------------------------------------------- } else { // Reset the insert index to the end of the FROM DisplayNode commandNode = queryDisplayComponent.getCommandDisplayNodeAtIndex(index); if (commandNode != null) { if (commandNode instanceof QueryDisplayNode) { DisplayNode whereNode = ((QueryDisplayNode)commandNode).getClauseDisplayNode(WHERE); DisplayNode fromNode = ((QueryDisplayNode)commandNode).getClauseDisplayNode(FROM); if (fromNode != null && whereNode == null) { index = fromNode.getEndIndex(); } } else if (commandNode instanceof DeleteDisplayNode) { DisplayNode optionNode = ((DeleteDisplayNode)commandNode).getClauseDisplayNode(OPTION); if (optionNode != null) { index = optionNode.getStartIndex(); } else { index = commandNode.getEndIndex(); } } else if (commandNode instanceof UpdateDisplayNode) { DisplayNode optionNode = ((UpdateDisplayNode)commandNode).getClauseDisplayNode(OPTION); if (optionNode != null) { index = optionNode.getStartIndex(); } else { index = commandNode.getEndIndex(); } } } // Get currently displayed SQL StringBuffer currentSQL = new StringBuffer(queryDisplayComponent.toString()); // Insert \n before inserting SQL to preserve \n formatting. while ((currentSQL.charAt(index) == '\n') || (currentSQL.charAt(index) == ';')) { index--; } // Insert Criteria String. Need to add one to index since index is pointing to last character // of the display node. currentSQL.insert(index + 1, SPACE + WHERE_STR + SPACE + criteriaString); setText(currentSQL.toString(), this); } setCaretOffset(0); // Fires Editor Event based on state of queryDisplayComponent // fireEditorEvent(); } } /** * This method launches the Expression Builder Dialog. If the current SQLTextPanel caret is currently within an Expression, * the Expression Builder is launched with the supplied expression. The supplied expression is replaced with the modified * expression when the function builder is dismissed. If the caret is not within an expression, the Function Builder is * launched without an expression. The resulting expression is inserted into the editor panel. */ public void launchCreateFunction() { int index = getCorrectedCaretOffset(); String functionName = null; int numArgs = 0; DisplayNode commandNode = queryDisplayComponent.getCommandDisplayNodeAtIndex(index); List nodeList = queryDisplayComponent.getDisplayNodesAtIndex(index); if( nodeList.size() == 1 ) { Object node = nodeList.get(0); if( node instanceof FunctionDisplayNode ) { IExpression expression = (IExpression)((FunctionDisplayNode)node).getLanguageObject(); if( expression instanceof IFunction ) { IFunction function = ((IFunction)expression); functionName = function.getName(); //System.out.println(" SqlEditorPanel.launchCreateFunction() Found function named: " + functionName); numArgs = function.getArgs().length; } } CreateFunctionAction action = new CreateFunctionAction(); action.run(functionName, numArgs); } } /** * Get the Group symbols for the command that the current cursor is within. This method superscedes the original method * getGroupsForBuilderTree() below which was insufficient to filtering or provided appropriate group symbols. * * @return List of group symbols in scope for the query that the index is within. */ public List getGroupsForBuilderTree( boolean forExpression ) { SqlIndexLocator indexLocator = new SqlIndexLocator(queryDisplayComponent, getCorrectedCaretOffset()); GroupSymbolFinder finder = new GroupSymbolFinder(indexLocator, externalBuilderGroups); return finder.find(); } /** * Method to determine if the panel has pending changes to the query. This just returns the status of the saveButton. * * @return true if the query has pending changes, false if not. */ public boolean hasPendingChanges() { return hasPendingChanges; } /** * Method to insert a list of element symbols at the specified index. If the clause that the index is in will not accept an * element, nothing is done. * * @param elementNames the list of new element names to insert * @param parentNames the list of corresponding parents for each element * @param index the index location to insert the element */ public void insertElements( List elementNames, List parentNames, int index, Object source ) { eventSource = source; // Dont allow insert within Expression - must use ExpressionBuilder boolean okToInsert = isInsertOK(index); if (!okToInsert) { return; } queryDisplayComponent.insertElements(elementNames, parentNames, index); // Refresh the EditorPanel, using the queryDisplayComponent refreshWithDisplayComponent(); // Fire Editor Event based on parsable state of query // fireEditorEvent(); } /** * Method to insert a list of element symbols at the end of the SELECT clause. * * @param elementNames the list of new element names to insert * @param parentNames the list of corresponding parents for each element */ public void insertElementsAtEndOfSelect( List elementNames, List parentNames, Object source ) { SelectDisplayNode selectNode = queryDisplayComponent.getSelectDisplayNode(); if (selectNode != null) { int selectEndIndex = selectNode.getEndIndex(); insertElements(elementNames, parentNames, selectEndIndex + 1, source); } else if (isDefaultQuery()) { String currentQuery = getText(); int insertIndex = currentQuery.toUpperCase().indexOf(ISQLConstants.SELECT) + ISQLConstants.SELECT.length(); insertElements(elementNames, parentNames, insertIndex, source); } else if (getText().trim().length() == 0) { StringBuffer sb = new StringBuffer(ISQLConstants.SELECT); // ------------------------------------------ // Add the list of Elements to the SELECT // ------------------------------------------ Iterator iter = elementNames.iterator(); while (iter.hasNext()) { String elemName = (String)iter.next(); sb.append(SPACE + elemName); if (iter.hasNext()) { sb.append(COMMA); } } sb.append(SPACE + ISQLConstants.FROM); // ------------------------------------------ // Add the list of Groupss to the FROM // ------------------------------------------ HashSet uniqueNames = new HashSet(); uniqueNames.addAll(parentNames); iter = uniqueNames.iterator(); while (iter.hasNext()) { String grpName = (String)iter.next(); sb.append(SPACE + grpName); if (iter.hasNext()) { sb.append(COMMA); } } setText(sb.toString(), source); } } /** * Check whether it is OK to insert at this location. Will display info message, saying that insert into expression is not * allowed. * * @param index the index location to check. * @return true if the insert is OK, false if not */ public boolean isInsertOK( int index ) { // Dont allow insert within Expression - must use ExpressionBuilder List nodes = queryDisplayComponent.getDisplayNodesAtIndex(index); if (nodes.size() == 1) { DisplayNode node = (DisplayNode)nodes.get(0); if (DisplayNodeUtils.isWithinSelect(node) && selectDropsEnabled == false) { return false; } else if (node.isInExpression()) { DisplayNode expressionNode = DisplayNodeUtils.getExpressionForNode(node); if (expressionNode != null && !(expressionNode instanceof AliasSymbolDisplayNode)) { // JOptionPane.showMessageDialog(this, propMgr.getText("stp.insertExpressionNotAllowedMsg"), // propMgr.getText("stp.insertNotAllowedTitle"),JOptionPane.INFORMATION_MESSAGE); return false; } } } else if (nodes.size() == 2) { DisplayNode node1 = (DisplayNode)nodes.get(0); DisplayNode node2 = (DisplayNode)nodes.get(1); if ((DisplayNodeUtils.isWithinSelect(node1) || DisplayNodeUtils.isWithinSelect(node1)) && selectDropsEnabled == false) { return false; } else if (node1.isInExpression() && node2.isInExpression()) { DisplayNode expressionNode = DisplayNodeUtils.getExpressionForNode(node1); if (expressionNode != null && !(expressionNode instanceof AliasSymbolDisplayNode)) { // JOptionPane.showMessageDialog(this, propMgr.getText("stp.insertExpressionNotAllowedMsg"), // propMgr.getText("stp.insertNotAllowedTitle"),JOptionPane.INFORMATION_MESSAGE); return false; } } } return true; } /** * Determines whether the current caret is within the SELECT clause * * @return true if the current caret is within the SELECT clause, false if not */ public boolean isCurrentCaretWithinSelect() { return isIndexWithin(getCorrectedCaretOffset(), DisplayNodeConstants.SELECT); } /** * Determines whether the current caret is within the FROM clause * * @return true if the current caret is within the FROM clause, false if not */ public boolean isCurrentCaretWithinFrom() { return isIndexWithin(getCorrectedCaretOffset(), FROM); } /** * Determines whether the index is anywhere within a DisplayNode of the specified type. * * @param index the cursor index * @param nodeType the type of DisplayNode * @return true if the cursor index is within the specified type, false if not */ public boolean isIndexWithin( int index, int nodeType ) { if (!isParsable()) { return false; } return DisplayNodeUtils.isIndexWithin(queryDisplayComponent.getDisplayNodeList(),index,nodeType); } /** * Determines whether the command that the cursor index is within has a Criteria Clause * * @param index the cursor index * @return true if the command has a Criteria clause, false if not */ public boolean commandHasCriteriaClause( int index ) { boolean result = false; if (isParsable()) { DisplayNode commandNode = queryDisplayComponent.getCommandDisplayNodeAtIndex(index); if (commandNode instanceof QueryDisplayNode) { if (((QueryDisplayNode)commandNode).getClauseDisplayNode(WHERE) != null) { result = true; } } else if (commandNode instanceof UpdateDisplayNode) { if (((UpdateDisplayNode)commandNode).getClauseDisplayNode(WHERE) != null) { result = true; } } else if (commandNode instanceof DeleteDisplayNode) { if (((DeleteDisplayNode)commandNode).getClauseDisplayNode(WHERE) != null) { result = true; } } } return result; } /** * Determines whether the current editor command is a Union (SetQuery) * * @return true if the command is a Union, false if not */ public boolean isCommandUnion() { boolean result = false; if (isParsable()) { ICommand command = queryDisplayComponent.getCommand(); if (command instanceof ISetQuery) { result = true; } } return result; } public DisplayNode getCurrentCommandDisplayNode() { return queryDisplayComponent.getCommandDisplayNodeAtIndex(getCorrectedCaretOffset()); } /** * Gets the index of the current Union segment. If the cursor is not currently within a segment, or the QueryDisplayComponent * is not a Union query, the returned index is -1. * * @return the current segment index, -1 for no segment. */ public int getCurrentUnionCommandSegmentIndex() { int index = -1; if (isCommandUnion()) { DisplayNode currentCommandDN = getCurrentCommandDisplayNode(); // Get the Union Command that the cursor is within if (currentCommandDN instanceof QueryDisplayNode) { SetQueryDisplayNode sqdn = (SetQueryDisplayNode)queryDisplayComponent.getDisplayNode(); return sqdn.getQueryDisplayNodes().indexOf(currentCommandDN); } } return index; } public boolean isSubQuerySelected() { // Get the Select Command that the cursor is within DisplayNode currentCommandDN = getCurrentCommandDisplayNode(); if (currentCommandDN instanceof QueryDisplayNode) { DisplayNode parent = currentCommandDN.getParent(); while (parent != null) { if (parent.getLanguageObject() instanceof ISubqueryContainer) { return true; } parent = parent.getParent(); } return false; } return false; } /** * Determines whether the command that the cursor index is within an editable Criteria Clause * * @param index the cursor index * @return true if the command has an editable Criteria clause, false if not */ public boolean commandHasEditableCriteriaClause( int index ) { // defect 14321 - Criteria Builder disabled when query has a where clause return commandHasCriteriaClause(index) && isEditable(); } /** * Determines whether the specified type can be inserted into the current displayComponent at the specified index. * * @param index the cursor index * @param type the type to insert * @return true if the type can be inserted at the index, false if not */ public boolean isInsertAllowed( int index, int type ) { if (!isParsable()) { return false; } return queryDisplayComponent.isInsertAllowed(index, type); } /** * Gets the ExpressionDisplayNode object at the specified position * * @return ExpressionDisplayNode at specified index, null if there is none */ public DisplayNode getExpressionAtIndex( int index ) { DisplayNode result = null; // -------------------------------------------------------------------- // Get the expression that the index is within, null if there is none. // -------------------------------------------------------------------- if (isParsable()) { List displayNodes = queryDisplayComponent.getDisplayNodeList(); result = DisplayNodeUtils.getNodeTypeAtIndex(displayNodes, index, EXPRESSION); // If an AliasSymbol is found, get the aliased expression if (result instanceof AliasSymbolDisplayNode) { result = result.getChildren().get(0); } } return result; } /** * Gets the CriteriaDisplayNode object at the current caret position. If the criteria is within another criteriaNode, the * getOuterMost parameter will walk the heirarchy to get the outermost criteria that the criteria is within. * * @param index the cursor index * @param getOuterMost 'true' to get outerMost criteria, 'false' if not * @return CriteriaDisplayNode at current caret, null if there is none */ public DisplayNode getCriteriaAtIndex( int index, boolean getOuterMost ) { DisplayNode result = null; if (isParsable()) { // ------------------------------------------------------------------ // If index is within a criteria, get it. // ------------------------------------------------------------------ List displayNodes = queryDisplayComponent.getDisplayNodeList(); result = DisplayNodeUtils.getNodeTypeAtIndex(displayNodes, index, CRITERIA); // ------------------------------------------------------------------ // If getOuterMost is desired, walk up through the heirarchy // ------------------------------------------------------------------ if (getOuterMost) { while (result != null) { DisplayNode parent = result.getParent(); if (parent != null && parent.getLanguageObject() instanceof ICriteria) { result = parent; } else { break; } } } // --------------------------------------------------------------------------- // If criteria not found yet, look for a WHERE clause in the current command // --------------------------------------------------------------------------- if (result == null) { DisplayNode commandNode = queryDisplayComponent.getCommandDisplayNodeAtIndex(index); if (commandNode != null && commandNode instanceof QueryDisplayNode) { DisplayNode clauseNode = ((QueryDisplayNode)commandNode).getClauseDisplayNode(WHERE); if (clauseNode != null) { result = ((WhereDisplayNode)clauseNode).getCriteria(); if (DisplayNodeUtils.isEditableCriteria(result)) { return result; } } } } } return result; } public List<IAction> getActions() { /* * jh note (8/22/2003): Find and Replace have been removed from this toolbar. * We are using Eclipse's Find/Replace action (in the Edit menu). */ if (actionList == null) { actionList = new ArrayList<IAction>(11); if (includedActionsList.contains(ACTION_ID_VALIDATE)) { validateAction = new Validate(this); validateAction.setToolTipText(Util.getString("SqlEditorPanel.Validate.tooltip")); //$NON-NLS-1$ actionList.add(validateAction); } if (includedActionsList.contains(ACTION_ID_LAUNCH_CRITERIA_BUILDER)) { launchCriteriaBuilderAction = new LaunchCriteriaBuilder(this); launchCriteriaBuilderAction.setToolTipText(Util.getString("SqlEditorPanel.LaunchCriteriaBuilder.tooltip")); //$NON-NLS-1$ actionList.add(launchCriteriaBuilderAction); } if (includedActionsList.contains(ACTION_ID_LAUNCH_EXPRESSION_BUILDER)) { launchExpressionBuilderAction = new LaunchExpressionBuilder(this); launchExpressionBuilderAction.setToolTipText(Util.getString("SqlEditorPanel.LaunchExpressionBuilder.tooltip")); //$NON-NLS-1$ actionList.add(launchExpressionBuilderAction); } if (includedActionsList.contains(ACTION_ID_EXPAND_SELECT)) { expandSelectAction = new ExpandSelect(this); expandSelectAction.setToolTipText(Util.getString("SqlEditorPanel.ExpandSelect.tooltip")); //$NON-NLS-1$ actionList.add(expandSelectAction); } if (includedActionsList.contains(ACTION_ID_UP_FONT)) { upFontAction = new UpFont(this); upFontAction.setToolTipText(Util.getString("SqlEditorPanel.UpFont.tooltip")); //$NON-NLS-1$ actionList.add(upFontAction); } if (includedActionsList.contains(ACTION_ID_DOWN_FONT)) { downFontAction = new DownFont(this); downFontAction.setToolTipText(Util.getString("SqlEditorPanel.DownFont.tooltip")); //$NON-NLS-1$ actionList.add(downFontAction); } if (includedActionsList.contains(ACTION_ID_TOGGLE_MESSAGE)) { toggleMessageAction = new ToggleMessage(this); toggleMessageAction.setToolTipText(Util.getString("SqlEditorPanel.ToggleMessage.tooltip")); //$NON-NLS-1$ actionList.add(toggleMessageAction); } if (includedActionsList.contains(ACTION_ID_TOGGLE_OPTIMIZER)) { toggleOptimizerAction = new ToggleOptimizer(this); toggleOptimizerAction.setToolTipText(Util.getString("SqlEditorPanel.ToggleOptimizer.tooltip")); //$NON-NLS-1$ actionList.add(toggleOptimizerAction); } if (includedActionsList.contains(ACTION_ID_IMPORT_FROM_FILE)) { importFromFileAction = new ImportFromFile(this); importFromFileAction.setToolTipText(Util.getString("SqlEditorPanel.ImportFromFile.tooltip")); //$NON-NLS-1$ actionList.add(importFromFileAction); } if (includedActionsList.contains(ACTION_ID_EXPORT_TO_FILE)) { exportToFileAction = new ExportToFile(this); exportToFileAction.setToolTipText(Util.getString("SqlEditorPanel.ExportToFile.tooltip")); //$NON-NLS-1$ actionList.add(exportToFileAction); } launchCreateFunctionAction = new LaunchCreateFunction(this); launchCreateFunctionAction.setToolTipText("Create Function"); //$NON-NLS-1$ } return actionList; } public static List getDefaultActionList() { return new ArrayList(Arrays.asList(DEFAULT_INCLUDED_ACTIONS)); } @Override public void dispose() { // remove prefStore listener IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); prefStore.removePropertyChangeListener(this); super.dispose(); } public int getCaretOffset() { return caretOffset; } public void setCaretOffset( int posn ) { // Prevent setting caret outside of current text if (posn < 0) { posn = 0; } int textLength = getText().length(); if (posn > textLength) { posn = textLength; } // set the caret offset this.caretOffset = posn; sqlTextViewer.getTextWidget().setCaretOffset(posn); setTextViewerBackgroundColors(posn); fireEditorInternalEvent(SqlEditorInternalEvent.CARET_CHANGED); } /* * Set the TextViewer Background Colors. If there are sub commands in the editor, the * selected command is shown in white, with the rest of the editor grayed out. Otherwise * the editor is completely white. * @param caretPosn the current caret offset position */ private void setTextViewerBackgroundColors( int caretPosn ) { // If it is NOT EDITABLE, we should do NOTHING here except delegate to the // primary bkgd coloring method if (!isEditable()) { setQueryTextBackground(); return; } // Is the caretPosn within a command if (isIndexWithin(caretPosn, COMMAND)) { // StyledText widget StyledText styledText = this.sqlTextViewer.getTextWidget(); int textLength = styledText.getText().length(); // Get the Command DisplayNode that its within DisplayNode wholeCommandNode = getQueryDisplayComponent().getDisplayNode(); // Get the Command DisplayNode that its within DisplayNode commandNode = getQueryDisplayComponent().getCommandDisplayNodeAtIndex(caretPosn); if (commandNode != null && !commandNode.equals(wholeCommandNode)) { // get start and end lines for entire text int wholeStartLine = 0; int wholeEndLine = styledText.getLineAtOffset(textLength); int nAllLines = wholeEndLine - wholeStartLine + 1; // get start and end lines for selected command int startIndex = commandNode.getStartIndex(); int endIndex = commandNode.getEndIndex(); int startLine = wholeStartLine; int endLine = wholeEndLine; if (startIndex >= 0 && endIndex <= textLength) { startLine = styledText.getLineAtOffset(startIndex); endLine = styledText.getLineAtOffset(endIndex); } int nLines = endLine - startLine + 1; // set background colors setSqlTextAreaBackgroundColor(colorManager.getColor(ColorManager.BACKGROUND_UNFOCUSED)); styledText.setLineBackground(wholeStartLine, nAllLines, colorManager.getColor(ColorManager.BACKGROUND_UNFOCUSED)); styledText.setLineBackground(startLine, nLines, colorManager.getColor(ColorManager.BACKGROUND_FOCUSED)); } else { // get start and end lines for entire text int wholeStartLine = 0; int wholeEndLine = styledText.getLineAtOffset(textLength); int nAllLines = wholeEndLine - wholeStartLine + 1; setSqlTextAreaBackgroundColor(colorManager.getColor(ColorManager.BACKGROUND_FOCUSED)); styledText.setLineBackground(wholeStartLine, nAllLines, colorManager.getColor(ColorManager.BACKGROUND_FOCUSED)); } // Union Query Highlighting if (wholeCommandNode instanceof SetQueryDisplayNode) { // get start and end lines for entire text List queryNodes = ((SetQueryDisplayNode)wholeCommandNode).getQueryDisplayNodes(); if (this.setQueryStates != null && this.setQueryStates.size() == queryNodes.size()) { // Iterate union query segments for (int i = 0; i < queryNodes.size(); i++) { boolean isReconciled = ((Boolean)this.setQueryStates.get(i)).booleanValue(); // if current segment is not reconciled, it's highlighted differently if (!isReconciled) { DisplayNode node = (DisplayNode)queryNodes.get(i); // get start and end lines for selected command int startIndex = node.getStartIndex(); int endIndex = node.getEndIndex(); // ensure that indices are legal if (startIndex >= 0 && endIndex <= textLength) { int startLine = styledText.getLineAtOffset(startIndex); int endLine = styledText.getLineAtOffset(endIndex); int nLines = endLine - startLine + 1; if (node.equals(commandNode)) { styledText.setLineBackground(startLine, nLines, colorManager.getColor(ColorManager.NON_RECD_UNION_QUERY_FOCUSED)); } else { styledText.setLineBackground(startLine, nLines, colorManager.getColor(ColorManager.NON_RECD_UNION_QUERY_UNFOCUSED)); } } } } } } } } void captureCaretInfo() { caretOffset = sqlTextViewer.getTextWidget().getCaretOffset(); caretYPosition = sqlTextViewer.getTextWidget().getLineAtOffset(caretOffset); caretXPosition = caretOffset - sqlTextViewer.getTextWidget().getOffsetAtLine(caretYPosition); setTextViewerBackgroundColors(caretOffset); fireEditorInternalEvent(SqlEditorInternalEvent.CARET_CHANGED); notifyCaretChanged(); } /** * Public method that ANY call to check if the cursor index is within a given node type needs to use this method. Invisible * nodes may be present (see OperationObjectEditorPage) that will make the visible cursor index not representative of the * actual index. * * @return * @since 5.0 */ public int getCorrectedCaretOffset() { return getCorrectedCaretOffset(caretOffset); } /** * public method that ANY call to check if the cursor index is within a given node type needs to use this method. Invisible * nodes may be present (see OperationObjectEditorPage) that will make the visible cursor index not representative of the * actual index. * * @return * @since 5.0 */ public int getCorrectedCaretOffset( int visibleCaretOffset ) { return queryDisplayComponent.getCorrectedIndex(visibleCaretOffset); } public TextViewer getTextViewer() { return sqlTextViewer; } public QueryDisplayComponent getQueryDisplayComponent() { return queryDisplayComponent; } public TextFontManager getFontManager() { if (tfmManager == null) { tfmManager = new TextFontManager(sqlTextViewer, new ScaledFontManager()); } return tfmManager; } public IUndoManager getUndoManager() { return this.textEditor.getUndoManager(); } /** * Expand the SELECT of the current query to include all elements. The current query is the query that the cursor is currently * within. */ public void expandCurrentSelect() { if (canExpandCurrentSelect()) { this.eventSource = this; int index = getCorrectedCaretOffset(); queryDisplayComponent.expandSelect(index); // Refresh the EditorPanel, using the queryDisplayComponent refreshWithDisplayComponent(); // Fires Editor Event based on state of queryDisplayComponent // fireEditorEvent(); } } /** * Tests whether the editor panel can expand the SELECT of the query that the cursor is currently in. The Query must be a * Select *, and the projected symbols of it cannot be zero. * * @return true if expandable, false otherwise */ public boolean canExpandCurrentSelect() { if (hasPendingChanges || selectExpansionEnabled == false) { return false; } int index = getCorrectedCaretOffset(); return queryDisplayComponent.canExpandSelect(index); } /** * Adjust the index where a string will be inserted into the query display component. If the arg index is within a word, index * will be moved to the end of the word. If the moved index is within an aliased symbol, index will be moved to end of aliased * symbol. * * @param index the desired index to do the insert * @return the adjusted index */ private int adjustIndexForInsert( int index ) { if (hasPendingChanges || !queryDisplayComponent.isParsable()) { return index; } // Get the clause that the index is within DisplayNode clauseNode = queryDisplayComponent.getQueryClauseAtIndex(index); if (clauseNode != null) { // ------------------------------------------------------------ // Get the DisplayNode that the original Index is in // ------------------------------------------------------------ List nodesAtIndex = DisplayNodeUtils.getDisplayNodesAtIndex(clauseNode.getDisplayNodeList(), index); int nNodes = nodesAtIndex.size(); DisplayNode node = null; if (nNodes == 1 || nNodes == 2) { node = ((DisplayNode)nodesAtIndex.get(0)); } else { return index; } // ------------------------------------------------------------ // If the node is within an AliasSymbol, dont break it up // ------------------------------------------------------------ if (node.getParent() != null && node.getParent() instanceof AliasSymbolDisplayNode) { node = node.getParent(); } // ------------------------------------------------------------ // Set the adjusted index after the node // ------------------------------------------------------------ return node.getEndIndex() + 1; } return index; } /** * Adjusts the string to be inserted based on the position of the index. The string is returned with commas before or after it * based on where it is being inserted. * * @param insertString the desired string to insert * @param index the index location to do the insert * @return the adjusted insert string, with leading or trailing commas */ private String adjustStringForInsert( String insertString, int index ) { if (hasPendingChanges || !queryDisplayComponent.isParsable()) { return insertString; } // Get the clause the the index is within DisplayNode clauseNode = queryDisplayComponent.getQueryClauseAtIndex(index); if (clauseNode != null) { // Get list of display nodes for this clause List displayNodes = clauseNode.getDisplayNodeList(); boolean isAtClauseStart = DisplayNodeUtils.isIndexAtClauseStart(clauseNode, index); boolean isAtClauseEnd = DisplayNodeUtils.isIndexAtClauseEnd(clauseNode, index); boolean isRightBeforeComma = DisplayNodeUtils.isIndexRightBeforeComma(displayNodes, index); boolean isRightAfterComma = DisplayNodeUtils.isIndexRightAfterComma(displayNodes, index); // ------------------------------------------------------------------------------------ // If inserting at Start of Clause, use leading space and trailing comma // ------------------------------------------------------------------------------------ if (isAtClauseStart) { return SPACE + insertString + COMMA; // ------------------------------------------------------------------------------------ // If inserting right after comma, use trailing comma // ------------------------------------------------------------------------------------ } else if (isRightAfterComma) { return insertString + COMMA; // ------------------------------------------------------------------------------------ // If inserting at End of Clause or right before a Comma, use only a leading comma // ------------------------------------------------------------------------------------ } else if (isAtClauseEnd || isRightBeforeComma) { return COMMA + insertString; // ------------------------------------------------------------------------------------ // Else just insert the string // ------------------------------------------------------------------------------------ } else { return insertString; } } return insertString; } public static int getVerticalRulerWidth() { return VERTICAL_RULER_WIDTH; } /** * Export the current string content of the sql display to a user-selected file */ public void exportToFile() { Shell shell = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); FileDialog dlg = new FileDialog(shell, SWT.SAVE); dlg.setFilterExtensions(new String[] {"*.*"}); //$NON-NLS-1$ dlg.setText(Util.getString(EXPORT_SQL_DIALOG_TITLE)); dlg.setFileName(Util.getString(EXPORT_DEFAULT_FILENAME)); String fileStr = dlg.open(); // If there is no file extension, add .sql if (fileStr != null && fileStr.indexOf('.') == -1) { fileStr = fileStr + "." + Util.getString(EXPORT_DEFAULT_FILEEXT); //$NON-NLS-1$ } if (fileStr != null) { FileWriter fw = null; BufferedWriter out = null; PrintWriter pw = null; try { fw = new FileWriter(fileStr); out = new BufferedWriter(fw); pw = new PrintWriter(out); String sqlText = getText(); pw.write(sqlText); } catch (Exception e) { String msg = Util.getString(EXPORT_PROBLEM); Util.log(IStatus.ERROR, e, msg); } finally { pw.close(); try { out.close(); } catch (java.io.IOException e) { } try { fw.close(); } catch (java.io.IOException e) { } } } } /** * Import into the sql display from a user-selected file */ public void importFromFile() { Shell shell = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); FileDialog dlg = new FileDialog(shell, SWT.OPEN); dlg.setFilterExtensions(new String[] {"*.sql;*.txt", "*.*"}); //$NON-NLS-1$ //$NON-NLS-2$ dlg.setText(Util.getString(IMPORT_SQL_DIALOG_TITLE)); String fileStr = dlg.open(); if (fileStr != null) { FileReader fr = null; BufferedReader in = null; try { fr = new FileReader(fileStr); in = new BufferedReader(fr); String str; StringBuffer all = new StringBuffer(); String delimiter = sqlTextViewer.getTextWidget().getLineDelimiter(); while ((str = in.readLine()) != null) { all.append(str); all.append(delimiter); } String sqlText = all.toString(); setText(sqlText, this); } catch (Exception e) { PluginUtil pluginUtil = UiPlugin.getDefault().getPluginUtil(); String msg = pluginUtil.getString(IMPORT_PROBLEM); pluginUtil.log(IStatus.ERROR, e, msg); String dialogMessage = msg + "\n" + e.getMessage(); //$NON-NLS-1$ displayError(shell, Util.getString(IMPORT_SQL_PROBLEM_DIALOG_TITLE), dialogMessage); } finally { try { if (fr != null) { fr.close(); } } catch (java.io.IOException e) { String msg = Util.getString(IMPORT_PROBLEM); Util.log(IStatus.ERROR, e, msg); } try { if (in != null) { in.close(); } } catch (java.io.IOException e) { String msg = Util.getString(IMPORT_PROBLEM); Util.log(IStatus.ERROR, e, msg); } } } } /** * Opens an error dialog to display the given message. * * @param message the error message to show */ private void displayError( final Shell shell, final String dialogTitle, final String message ) { shell.getDisplay().syncExec(new Runnable() { @Override public void run() { MessageDialog.openError(shell, dialogTitle, message); } }); } @Override public void widgetSelected( SelectionEvent e ) { captureCaretInfo(); } @Override public void widgetDefaultSelected( SelectionEvent e ) { captureCaretInfo(); } @Override public void selectionChanged( SelectionChangedEvent e ) { } @Override public void mouseUp( MouseEvent e ) { captureCaretInfo(); } @Override public void mouseDown( MouseEvent e ) { } @Override public void mouseDoubleClick( MouseEvent e ) { captureCaretInfo(); } @Override public void keyPressed( KeyEvent e ) { } @Override public void keyReleased( KeyEvent e ) { captureCaretInfo(); } // Handler for DocumentEvents - // Whenever the document changes, check vs previous SQL unless already pending changes class DocumentChangeListener implements IDocumentListener { @Override public void documentAboutToBeChanged( DocumentEvent event ) { } @Override public void documentChanged( DocumentEvent event ) { // -------------------------------------------------------------- // If this is a validation, fire event regardless of SQL // -------------------------------------------------------------- if (validateSelected || isCompleteRefresh) { validateSelected = false; isCompleteRefresh = false; hasPendingChanges = false; savedSql = getText(); fireEditorInternalEvent(SqlEditorInternalEvent.TEXT_RESET); fireEditorEvent(); // -------------------------------------------------------------- // Determine whether changes Pending need to be fired // -------------------------------------------------------------- } else if (!hasPendingChanges) { // Check whether the new Sql has changed String newSql = getText(); boolean sqlChanged = hasSqlChanged(newSql.trim()); savedSql = newSql; // SqlChanged if (sqlChanged) { setHasPendingChanges(); } } } boolean hasSqlChanged( String newSql ) { return TransformationHelper.stringsDifferent(newSql, savedSql); } } public int getCaretYPosition() { return this.caretYPosition; } public int getCaretXPosition() { return this.caretXPosition; } public void setHasPendingChanges() { hasPendingChanges = true; setMessage(QUERY_CHANGES_PENDING_MESSAGE); fireEditorInternalEvent(SqlEditorInternalEvent.TEXT_CHANGED); fireEditorEvent(); } public void setPanelType(int type) { this.panelType = type; } public int getPanelType() { return this.panelType; } }