001: /* ====================================================================
002: * The JRefactory License, Version 1.0
003: *
004: * Copyright (c) 2001 JRefactory. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by the
021: * JRefactory (http://www.sourceforge.org/projects/jrefactory)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "JRefactory" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please contact seguin@acm.org.
028: *
029: * 5. Products derived from this software may not be called "JRefactory",
030: * nor may "JRefactory" appear in their name, without prior written
031: * permission of Chris Seguin.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE CHRIS SEGUIN OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of JRefactory. For more information on
049: * JRefactory, please see
050: * <http://www.sourceforge.org/projects/jrefactory>.
051: */
052: package org.acm.seguin.ide.jdeveloper;
053:
054: import java.io.File;
055: import java.io.PrintWriter;
056: import java.io.StringWriter;
057: import javax.swing.Icon;
058: import javax.swing.ImageIcon;
059: import javax.swing.JMenu;
060: import javax.swing.JMenuItem;
061: import oracle.ide.ContextMenu;
062: import oracle.ide.Ide;
063: import oracle.ide.IdeAction;
064: import oracle.ide.addin.Addin;
065: import oracle.ide.addin.Context;
066: import oracle.ide.addin.ContextMenuListener;
067: import oracle.ide.addin.Controller;
068: import oracle.ide.addin.View;
069: import oracle.ide.editor.Editor;
070: import oracle.ide.editor.EditorFrame;
071: import oracle.javatools.editor.BasicEditorPane;
072: import oracle.jdeveloper.ceditor.find.FindableEditor;
073: import org.acm.seguin.pretty.PrettyPrintFromIDE;
074: import org.acm.seguin.tools.install.PrettyPrinterConfigGUI;
075: import org.acm.seguin.tools.RefactoryInstaller;
076:
077: /**
078: * The PrettyPrinter Extension for Oracle jDeveloper 9i.
079: *
080: * @author Guenther Bodlak
081: * @created 30. Mai 2002
082: */
083: public class JDeveloperPrettyPrinter extends PrettyPrintFromIDE
084: implements Addin, Controller {
085: private final static String PRETTY_PRINTER_MENU_ICON = "/org/acm/seguin/ide/jdeveloper/PrettyPrinter.gif";
086: private final static int PRETTY_PRINTER_COMMAND_ID = Ide
087: .newSysCmd("MyCommand.MY_MENU_COMMAND");
088: private final static int PRETTY_PRINTER_GUI_ID = Ide
089: .newSysCmd("MyCommand.MY_MENU_COMMAND");
090: private final static float PRETTY_PRINTER_ADDIN_VERSION = 1.0f;
091:
092: private BasicEditorPane _oCurrentEditorPane = null;
093:
094: /**
095: * Constructor for the JDeveloperPrettyPrinter object
096: */
097: public JDeveloperPrettyPrinter() {
098: super ();
099: }
100:
101: /**
102: * Loads the icon.
103: *
104: * @param gifName Description of the Parameter
105: * @return the Icon
106: */
107: public final static Icon doLoadIcon(String gifName) {
108:
109: Icon anIcon = null;
110: java.net.URL imgURL = JDeveloperPrettyPrinter.class
111: .getResource(gifName);
112: if (imgURL != null) {
113: anIcon = new ImageIcon(imgURL);
114: } else {
115: System.out.println("Error with Icon " + gifName);
116: }
117: return anIcon;
118: }
119:
120: /**
121: * Description of the Method
122: *
123: * @param context Description of the Parameter
124: * @param extension Description of the Parameter
125: * @return Description of the Return Value
126: */
127: public static boolean NodeIsFileType(Context context,
128: String extension) {
129: oracle.ide.model.Element element = (context == null) ? null
130: : context.getElement();
131: if (element != null) {
132: if (element instanceof oracle.ide.model.Locatable) {
133: java.net.URL url = ((oracle.ide.model.Locatable) element)
134: .getURL();
135: if (url.getProtocol().equals("file")) {
136: String fileName = url.getFile();
137: return (extension == null) ? true : fileName
138: .endsWith(extension);
139: }
140: }
141: }
142: return false;
143: }
144:
145: /**
146: * This method is called to see if a Menu should be Enabled or Disabled The
147: * code here can be arbitrarily complex to determine the availability.
148: *
149: * @param context - the Current Context to examine to determine true/false
150: * result
151: * @return <code>true</code> if the Action should be enabled, <code>false</code>
152: * otherwise
153: */
154: public static boolean isMenuAvailable(Context context) {
155: return NodeIsFileType(context, ".java");
156: }
157:
158: /**
159: * The AddinManager calls this method to request the version number of this
160: * addin <code>(1.0f)</code>. <br>
161: * This is different then the <code>ideVersion</code> which represents the
162: * version of the JDeveloper IDE for which this Addin was written and
163: * tested against.
164: *
165: * @return the version number of this Addin <code>(e.g. 1.0f)</code>. <br>
166: */
167: public float version() {
168: return PRETTY_PRINTER_ADDIN_VERSION;
169: }
170:
171: /**
172: * The AddinManager calls this method to request the IDE version number for
173: * which this Addin was written and tested against. <br>
174: * Returning the wrong version number will tell the IDE to reject this
175: * Addin and not load it. <br>
176: * Note: This is different then the <code>version</code> method which
177: * represents the version number for this particular Addin. <br>
178: *
179: * @return the IDE version number <code>oracle.ide.Ide.IDE_VERSION</code>.
180: */
181: public float ideVersion() {
182: return oracle.ide.Ide.IDE_VERSION;
183: }
184:
185: /**
186: * The AddinManager calls this method to see if this Addin is ready to shut
187: * down before the IDE terminates. <br>
188: *
189: * @return allways true
190: */
191: public boolean canShutdown() {
192: return true;
193: }
194:
195: /**
196: * The AddinManager calls this method to allow an Addin to release any
197: * resources held before the IDE shuts down. This can include things such
198: * as saving the state of the Addin, Closing connections, etc. *
199: */
200: public void shutdown() {
201: }
202:
203: /**
204: * The AddinManager calls this method at startup time to allow
205: * initialization.
206: */
207: public void initialize() {
208: // Home-Dir for .Refactory dir is lib/ext
209: String sJRefactoryHome = Ide.getHomeDirectory()
210: + File.separator + "lib" + File.separator + "ext";
211: System.getProperties().setProperty("jrefactory.home",
212: sJRefactoryHome);
213:
214: // Is the User allowed to configure the settings?
215: // If there is a file ".NoConfig" we don't show the "PrettyPrinter Options" menu
216: File oFile = new File(sJRefactoryHome + File.separator
217: + ".Refactory" + File.separator + ".NoConfig");
218: if (!oFile.exists()) {
219: Controller ctrlr = this ;
220: IdeAction mainMenuAction = doCreateIdeAction(ctrlr,
221: "PrettyPrinter Options", null,
222: PRETTY_PRINTER_MENU_ICON);
223: JMenu mainMenu = oracle.ide.MainWindow.Tools;
224: mainMenu.add(mainMenuAction);
225: }
226:
227: // Create the Context Menu Item and add it to the Editor Menu
228: JMenuItem rclickMi1 = doCreateMenuItem(this ,
229: PRETTY_PRINTER_COMMAND_ID, "Reformat Code",
230: new Integer('R'), PRETTY_PRINTER_MENU_ICON);
231: ctxMenuListener ctxMenuLstnr1 = new ctxMenuListener(rclickMi1);
232: Ide.getEditorManager().getContextMenu().addContextMenuListener(
233: ctxMenuLstnr1);
234: }
235:
236: /**
237: * Gets the supervising controller if any associated with this Controller.
238: * This method allows multiple custom/specific controllers to allow common
239: * processing for update()/checkCommands() to be done by a common
240: * Controller (supervisor).
241: *
242: * @return null
243: */
244: public Controller super visor() {
245: return null;
246: }
247:
248: /**
249: * We call the PrettyPrinter ...
250: *
251: * @param action action the IdeAction whose command (ID) is to be executed.
252: * @param context the current context under which this action has been invoked.
253: * @return <code>true</code> if method carried out the specified
254: * command, otherwise return <code>false</code>.
255: */
256: public boolean handleEvent(IdeAction action, Context context) {
257: try {
258: int cmdId = action.getCommandId();
259: if (cmdId == PRETTY_PRINTER_COMMAND_ID) {
260: setCurrentEditorPane(context);
261: if (getCurrentEditorPane().isEditable()) {
262: // call the PrettyPrinter
263: prettyPrintCurrentWindow();
264: return true;
265: } else {
266: Ide
267: .getLogWindow()
268: .log(
269: "PrettyPrinter: selected File is write protected!");
270: }
271: } else if (cmdId == PRETTY_PRINTER_GUI_ID) {
272: // Make sure everything is installed properly
273: (new RefactoryInstaller(false)).run();
274:
275: // Start the config gui ...
276: (new PrettyPrinterConfigGUI(false)).run();
277:
278: return true;
279: }
280: } catch (Throwable e) {
281: StringWriter oStringWriter = new StringWriter();
282: e.printStackTrace(new PrintWriter(oStringWriter));
283: Ide.getLogWindow().log(oStringWriter.toString());
284: }
285: return false;
286: }
287:
288: /**
289: * This method updates the enabled status of the specified action within
290: * the specified context.
291: *
292: * @param action action whose command is to be executed.
293: * @param context the current context
294: * @return true if the controller handles the specified command.
295: */
296: public boolean update(IdeAction action, Context context) {
297: int cmdId = action.getCommandId();
298: if (cmdId == PRETTY_PRINTER_COMMAND_ID
299: || cmdId == PRETTY_PRINTER_GUI_ID) {
300: if (isMenuAvailable(context)) {
301: action.setEnabled(true);
302: return true;
303: }
304: }
305: return false;
306: }
307:
308: /**
309: * checkCommands() should be called on the controller associated with the
310: * active view whenever the Context changes.
311: *
312: * @param context the current context. Null values are acceptable.
313: * @param activeController the controller associated with the active view.
314: * Null values are acceptable.
315: */
316: public void checkCommands(Context context,
317: Controller activeController) {
318: return;
319: }
320:
321: /**
322: * Sets the stringInIDE attribute of the PrettyPrinterAddin object
323: *
324: * @param value The new stringInIDE value
325: */
326: protected void setStringInIDE(String value) {
327: // replacing the text is much faster than setText()!
328: _oCurrentEditorPane.selectAll();
329: _oCurrentEditorPane.replaceSelection(value);
330: }
331:
332: /**
333: * Gets the stringFromIDE attribute of the PrettyPrinterAddin object
334: *
335: * @return The stringFromIDE value
336: */
337: protected String getStringFromIDE() {
338: return _oCurrentEditorPane.getText();
339: }
340:
341: /**
342: * Gets the lineNumber attribute of the PrettyPrinterAddin object
343: *
344: * @return The lineNumber value
345: */
346: protected int getLineNumber() {
347: int iLine = _oCurrentEditorPane
348: .getLineFromOffset(_oCurrentEditorPane
349: .getCaretPosition()) + 1;
350: return iLine;
351: }
352:
353: /**
354: * Sets the lineNumber attribute of the PrettyPrinterAddin object
355: *
356: * @param iLine The new lineNumber value
357: */
358: protected void setLineNumber(int iLine) {
359: if (iLine - 1 >= 0) {
360: _oCurrentEditorPane.setCaretPosition(_oCurrentEditorPane
361: .getLineStartOffset(iLine - 1));
362: }
363: }
364:
365: /**
366: * Creates the menu item.
367: *
368: * @param ctrlr Description of the Parameter
369: * @param cmdID Description of the Parameter
370: * @param menuLabel Description of the Parameter
371: * @param mnemonic Description of the Parameter
372: * @param iconName Description of the Parameter
373: * @return Description of the Return Value
374: */
375: private static JMenuItem doCreateMenuItem(Controller ctrlr,
376: int cmdID, String menuLabel, Integer mnemonic,
377: String iconName) {
378: Icon mi = new ImageIcon(ctrlr.getClass().getResource(iconName));
379: // This can be retrieved via IdeAction.find( ADD_COMMENT_CMD_ID )
380: IdeAction actionTM = IdeAction.create(cmdID, null, menuLabel,
381: mnemonic, null, mi, null, true);
382: actionTM.setController(ctrlr);
383: // To Set the Accelerator, uncomment line below
384: //actionTM.putValue(IdeAction.ACCELERATOR, accelerator);
385: // To Set the Tool Tip, uncomment line below
386: //actionTM.putValue( javax.swing.Action.SHORT_DESCRIPTION, menuLabel );
387: JMenuItem menuItem = Ide.getMenubar().createMenuItem(actionTM);
388: return menuItem;
389: }
390:
391: /**
392: * Description of the Method
393: *
394: * @param ctrlr Description of the Parameter
395: * @param menuLabel Description of the Parameter
396: * @param mnemonic Description of the Parameter
397: * @param iconName Description of the Parameter
398: * @return Description of the Return Value
399: */
400: private static IdeAction doCreateIdeAction(Controller ctrlr,
401: String menuLabel, Integer mnemonic, String iconName) {
402: // Icon associated with this IdeAction
403: Icon anIcon = doLoadIcon(iconName);
404: // Accelerator (if any) associated with this IdeAction
405: javax.swing.KeyStroke accelerator = null;
406: // Name of class which extends oracle.ide.addin.AbstractCommand
407: String cmdClass = null;
408:
409: // This can be retrieved via IdeAction.find( PRETTY_PRINTER_GUI_ID )
410: IdeAction myCmdAction = IdeAction.get(PRETTY_PRINTER_GUI_ID,
411: cmdClass, menuLabel, mnemonic, accelerator, anIcon,
412: null, true);
413:
414: //To set the Action Category (Tools | IDE Preferences | Accelerators ), uncomment next line
415: //myCmdAction.putValue(IdeAction.CATEGORY, categoryName );
416:
417: //To set an Accelerator , uncomment next line
418: //myCmdAction.putValue(IdeAction.ACCELERATOR, accelerator);
419:
420: //To set the Tool Tip (used to ToolBars, etc), uncomment next line
421: //myCmdAction.putValue( javax.swing.Action.SHORT_DESCRIPTION, menuLabel );
422:
423: myCmdAction.setController(ctrlr);
424: return myCmdAction;
425: }
426:
427: /**
428: * Gets the currentEditorPane attribute of the PrettyPrinterAddin object
429: *
430: * @return The currentEditorPane value
431: */
432: private BasicEditorPane getCurrentEditorPane() {
433: return _oCurrentEditorPane;
434: }
435:
436: /**
437: * Sets the currentEditorPane attribute of the PrettyPrinterAddin object
438: *
439: * @param context The new currentEditorPane value
440: */
441: private void setCurrentEditorPane(Context context) {
442: BasicEditorPane editorPane = null;
443: if (context != null) {
444: View view = context.getView();
445: FindableEditor findableEditor = null;
446: if (view instanceof EditorFrame) {
447: // If the current view is on an editor frame, then check
448: // if the active editor supports the Find package.
449: EditorFrame editorFrame = (EditorFrame) view;
450: Editor editor = editorFrame.getCurrentEditor();
451: if (editor instanceof FindableEditor) {
452: findableEditor = (FindableEditor) editor;
453: }
454: } else if (view instanceof FindableEditor) {
455: // If the current view is an editor itself, then check
456: // if it supports the Find package.
457: findableEditor = (FindableEditor) view;
458: }
459: // If the current view supports the find interface, get the
460: // editor pane that has focus.
461: if (findableEditor != null) {
462: editorPane = findableEditor.getFocusedEditorPane();
463: }
464: }
465: _oCurrentEditorPane = editorPane;
466: }
467:
468: /**
469: * Description of the Class
470: *
471: * @author Günther Bodlak
472: * @created 30. Mai 2002
473: */
474: private final static class ctxMenuListener implements
475: ContextMenuListener {
476: private JMenuItem menuItem;
477:
478: /**
479: * Constructor for the ctxMenuListener object
480: *
481: * @param ctxMenuItem Description of the Parameter
482: */
483: ctxMenuListener(JMenuItem ctxMenuItem) {
484: this .menuItem = ctxMenuItem;
485: }
486:
487: /**
488: * Allow a ContextMenuListener to initialize itself before Context Menu
489: * is displayed.
490: *
491: * @param popup the current contextMenu (container) which is about to
492: * be displayed
493: */
494: public void poppingUp(ContextMenu popup) {
495: Context context = (popup == null) ? null : popup
496: .getContext();
497: if (context == null) {
498: return;
499: }
500:
501: // Insert the MenuItem in this Menu!
502: // We could add the menu un-conditionally and then disable it,
503: // But this is not always a good practice for context menus!
504: if (isMenuAvailable(context)) {
505: // If it should be enabled, then display it!
506: // Otherwise, dont bother showing menus that will be disabled!
507: popup.add(this .menuItem);
508: }
509: return;
510: }
511:
512: /**
513: * Allow a ContextMenuListener to do any cleanup nessecitated by the
514: * the <code>poppingUp</code> method.
515: *
516: * @param popup the current contextMenu item + <code>this</code> to
517: * operate on
518: */
519: public void poppingDown(ContextMenu popup) {
520: }
521:
522: /**
523: * If this Context Menu Item is the "Default" Action when user double
524: * clicks on an item. It should be realized that on any given Context
525: * Menu, there are many different available commands and only ONE can
526: * be the default cammand. Thus most implementation of this method
527: * should simply return <code>false</code> as they are not the default
528: * double click action command.
529: *
530: * @param context Description of the Parameter
531: * @return Description of the Return Value
532: */
533: public boolean handleDefaultAction(Context context) {
534: return false;
535: }
536: }
537: }
|