File Source: UIUtilities.java

     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.addons.ui_swing;
    24  
    25  import com.dmdirc.logger.ErrorLevel;
    26  import com.dmdirc.logger.Logger;
    27  import com.dmdirc.addons.ui_swing.actions.RedoAction;
    28  import com.dmdirc.addons.ui_swing.actions.UndoAction;
    29  import com.dmdirc.addons.ui_swing.components.DMDircUndoableEditListener;
    30  import com.dmdirc.util.ReturnableThread;
    31  
    32  import java.awt.Dimension;
    33  import java.awt.FontMetrics;
    34  import java.awt.event.KeyEvent;
    35  import java.lang.reflect.InvocationTargetException;
    36  
    37  import javax.swing.BorderFactory;
    38  import javax.swing.JComponent;
    39  import javax.swing.KeyStroke;
    40  import javax.swing.SwingUtilities;
    41  import javax.swing.UIManager;
    42  import javax.swing.UIManager.LookAndFeelInfo;
    43  import javax.swing.UnsupportedLookAndFeelException;
    44  import javax.swing.text.JTextComponent;
    45  import javax.swing.undo.UndoManager;
    46  
    47  import net.miginfocom.layout.PlatformDefaults;
    48  
    49  /**
    50   * UI constants.
    51   */
    52  public final class UIUtilities {
    53  
    54      /** Size of a large border. */
    55      public static final int LARGE_BORDER = 10;
    56      /** Size of a small border. */
    57      public static final int SMALL_BORDER = 5;
    58      /** Standard button size. */
             /* 
    P/P       *  Method: com.dmdirc.addons.ui_swing.UIUtilities__static_init
              * 
              *  Postconditions:
              *    BUTTON_SIZE == &new Dimension(UIUtilities__static_init#1)
              *    new Dimension(UIUtilities__static_init#1) num objects == 1
              */
    59      public static final Dimension BUTTON_SIZE = new Dimension(100, 25);
    60  
    61      /** Not intended to be instatiated. */
             /* 
    P/P       *  Method: void com.dmdirc.addons.ui_swing.UIUtilities()
              */
    62      private UIUtilities() {
    63      }
    64  
    65      /**
    66       * Adds an undo manager and associated key bindings to the specified text
    67       * component.
    68       * 
    69       * @param component component Text component to add an undo manager to
    70       */
    71      public static void addUndoManager(final JTextComponent component) {
                 /* 
    P/P           *  Method: void addUndoManager(JTextComponent)
                  * 
                  *  Preconditions:
                  *    component != null
                  * 
                  *  Presumptions:
                  *    javax.swing.text.JTextComponent:getActionMap(...)@79 != null
                  *    javax.swing.text.JTextComponent:getActionMap(...)@85 != null
                  *    javax.swing.text.JTextComponent:getDocument(...)@75 != null
                  *    javax.swing.text.JTextComponent:getInputMap(...)@82 != null
                  *    javax.swing.text.JTextComponent:getInputMap(...)@88 != null
                  */
    72          final UndoManager undoManager = new UndoManager();
    73  
    74          // Listen for undo and redo events
    75          component.getDocument().addUndoableEditListener(
    76                  new DMDircUndoableEditListener(undoManager));
    77  
    78          // Create an undo action and add it to the text component
    79          component.getActionMap().put("Undo", new UndoAction(undoManager));
    80  
    81          // Bind the undo action to ctl-Z
    82          component.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
    83  
    84          // Create a redo action and add it to the text component
    85          component.getActionMap().put("Redo", new RedoAction(undoManager));
    86  
    87          // Bind the redo action to ctl-Y
    88          component.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
    89      }
    90  
    91      /**
    92       * Initialises any settings required by this UI (this is always called
    93       * before any aspect of the UI is instansiated).
    94       *
    95       * @throws UnsupportedOperationException If unable to switch to the system
    96       * look and feel
    97       */
    98      public static void initUISettings() {
    99  
   100          try {
   101  
                     /* 
    P/P               *  Method: void initUISettings()
                      * 
                      *  Presumptions:
                      *    (int) (net.miginfocom.layout.UnitValue:getValue(...)@130) in {-231..232-1}
                      *    net.miginfocom.layout.PlatformDefaults:getPanelInsets(...)@130 != null
                      */
   102              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
   103          } catch (InstantiationException ex) {
   104              throw new UnsupportedOperationException("Unable to switch to the " +
   105                      "system look and feel", ex);
   106          } catch (ClassNotFoundException ex) {
   107              throw new UnsupportedOperationException("Unable to switch to the " +
   108                      "system look and feel", ex);
   109          } catch (UnsupportedLookAndFeelException ex) {
   110              throw new UnsupportedOperationException("Unable to switch to the " +
   111                      "system look and feel", ex);
   112          } catch (IllegalAccessException ex) {
   113              throw new UnsupportedOperationException("Unable to switch to the " +
   114                      "system look and feel", ex);
   115          }
   116  
   117          UIManager.put("swing.useSystemFontSettings", true);
   118          if (getTabbedPaneOpaque()) {
   119              // If this is set on windows then .setOpaque seems to be ignored
   120              // and still used as true
   121              UIManager.put("TabbedPane.contentOpaque", false);
   122          }
   123          UIManager.put("swing.boldMetal", false);
   124          UIManager.put("InternalFrame.useTaskBar", false);
   125          UIManager.put("SplitPaneDivider.border",
   126                  BorderFactory.createEmptyBorder());
   127          UIManager.put("Tree.scrollsOnExpand", true);
   128          UIManager.put("Tree.scrollsHorizontallyAndVertically", true);
   129          UIManager.put("SplitPane.border", BorderFactory.createEmptyBorder());
   130          UIManager.put("SplitPane.dividerSize", (int) PlatformDefaults.getPanelInsets(0).getValue());
   131          UIManager.put("TreeUI", "javax.swing.plaf.metal.MetalTreeUI");
   132          PlatformDefaults.setDefaultRowAlignmentBaseline(false);
   133      }
   134  
   135      /**
   136       * Returns the class name of the look and feel from its display name.
   137       *
   138       * @param displayName Look and feel display name
   139       *
   140       * @return Look and feel class name or a zero length string
   141       */
   142      public static String getLookAndFeel(final String displayName) {
                 /* 
    P/P           *  Method: String getLookAndFeel(String)
                  * 
                  *  Presumptions:
                  *    arr$.length@150 <= 232-1
                  *    arr$[i$]@150 != null
                  *    javax.swing.UIManager:getInstalledLookAndFeels(...)@150 != null
                  *    javax.swing.UIManager_LookAndFeelInfo:getName(...)@151 != null
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    displayName: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:equals(...)@143: {0}, {1}
                  *    java.lang.String:equals(...)@151: {0}, {1}
                  *    java.lang.String:isEmpty(...)@143: {1}, {0}
                  *    java.lang.StringBuilder:length(...)@157: {-231..-1, 1..232-1}, {0}
                  */
   143          if (displayName == null || displayName.isEmpty() ||
   144                  "Native".equals(displayName)) {
   145              return UIManager.getSystemLookAndFeelClassName();
   146          }
   147  
   148          final StringBuilder classNameBuilder = new StringBuilder();
   149  
   150          for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
   151              if (laf.getName().equals(displayName)) {
   152                  classNameBuilder.append(laf.getClassName());
   153                  break;
   154              }
   155          }
   156  
   157          if (classNameBuilder.length() == 0) {
   158              classNameBuilder.append(UIManager.getSystemLookAndFeelClassName());
   159          }
   160  
   161          return classNameBuilder.toString();
   162      }
   163  
   164      /**
   165       * Invokes and waits for the specified runnable, executed on the EDT.
   166       * 
   167       * @param runnable Thread to be executed
   168       */
   169      public static void invokeAndWait(final Runnable runnable) {
                 /* 
    P/P           *  Method: void invokeAndWait(Runnable)
                  * 
                  *  Preconditions:
                  *    (soft) runnable != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.logger.ErrorLevel.HIGH)
                  * 
                  *  Test Vectors:
                  *    javax.swing.SwingUtilities:isEventDispatchThread(...)@170: {0}, {1}
                  */
   170          if (SwingUtilities.isEventDispatchThread()) {
   171              runnable.run();
   172          } else {
   173              try {
   174                  SwingUtilities.invokeAndWait(runnable);
   175              } catch (InterruptedException ex) {
   176              //Ignore
   177              } catch (InvocationTargetException ex) {
   178                  Logger.appError(ErrorLevel.HIGH, "Unable to execute thread.", ex);
   179              }
   180          }
   181      }
   182  
   183      /**
   184       * Invokes and waits for the specified runnable, executed on the EDT.
   185       * 
   186       * @param <T> The return type of the returnable thread
   187       * @param returnable Thread to be executed
   188       * @return Result from the compelted thread
   189       */
   190      public static <T> T invokeAndWait(final ReturnableThread<T> returnable) {
                 /* 
    P/P           *  Method: Object invokeAndWait(ReturnableThread)
                  * 
                  *  Preconditions:
                  *    returnable != null
                  * 
                  *  Presumptions:
                  *    init'ed(com.dmdirc.logger.ErrorLevel.HIGH)
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    javax.swing.SwingUtilities:isEventDispatchThread(...)@191: {0}, {1}
                  */
   191          if (SwingUtilities.isEventDispatchThread()) {
   192              returnable.run();
   193          } else {
   194              try {
   195                  SwingUtilities.invokeAndWait(returnable);
   196              } catch (InterruptedException ex) {
   197                  //Ignore
   198              } catch (InvocationTargetException ex) {
   199                  Logger.appError(ErrorLevel.HIGH, "Unable to execute thread.", ex);
   200              }            
   201          }
   202          
   203          return returnable.getObject();
   204      }
   205  
   206      /**
   207       * Queues the runnable to be executed on the EDT.
   208       * 
   209       * @param runnable Runnable to be executed.
   210       */
   211      public static void invokeLater(final Runnable runnable) {
                 /* 
    P/P           *  Method: void invokeLater(Runnable)
                  * 
                  *  Preconditions:
                  *    (soft) runnable != null
                  * 
                  *  Test Vectors:
                  *    javax.swing.SwingUtilities:isEventDispatchThread(...)@212: {0}, {1}
                  */
   212          if (SwingUtilities.isEventDispatchThread()) {
   213              runnable.run();
   214          } else {
   215              SwingUtilities.invokeLater(runnable);
   216          }
   217      }
   218  
   219      /**
   220       * Check if we are using one of the Windows Look and Feels
   221       * 
   222       * @return True iff the current LAF is "Windows" or "Windows Classic"
   223       */
   224      public static boolean isWindowsUI() {
                 /* 
    P/P           *  Method: bool isWindowsUI()
                  * 
                  *  Presumptions:
                  *    java.lang.Object:getClass(...)@225 != null
                  *    javax.swing.UIManager:getLookAndFeel(...)@225 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   225          final String uiname = UIManager.getLookAndFeel().getClass().getName();
   226          final String windows =
   227                  "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
   228          final String classic =
   229                  "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";
   230  
   231          return windows.equals(uiname) || classic.equals(uiname);
   232      }
   233  
   234      /**
   235       * Get the value to pass to set Opaque on items being added to a JTabbedPane
   236       * 
   237       * @return True iff the current LAF is not Windows or OS X.
   238       * @since 0.6
   239       */
   240      public static boolean getTabbedPaneOpaque() {
                 /* 
    P/P           *  Method: bool getTabbedPaneOpaque()
                  * 
                  *  Presumptions:
                  *    java.lang.Object:getClass(...)@241 != null
                  *    javax.swing.UIManager:getLookAndFeel(...)@241 != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   241          final String uiname = UIManager.getLookAndFeel().getClass().getName();
   242          final String windows =
   243                  "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
   244          final String nimbus = "sun.swing.plaf.nimbus.NimbusLookAndFeel";
   245  
   246          return !(windows.equals(uiname) || Apple.isAppleUI() || nimbus.equals(
   247                  uiname));
   248      }
   249      
   250      /**
   251       * Get the DOWN_MASK for the command/ctrl key.
   252       * 
   253       * @return on OSX this returns META_DOWN_MASK, else CTRL_DOWN_MASK
   254       * @since 0.6
   255       */
   256      public static int getCtrlDownMask() {
                 /* 
    P/P           *  Method: int getCtrlDownMask()
                  * 
                  *  Postconditions:
                  *    return_value == One-of{256, 128}
                  *    return_value in {128, 256}
                  */
   257          return Apple.isAppleUI() ? KeyEvent.META_DOWN_MASK : KeyEvent.CTRL_DOWN_MASK;
   258      }
   259      
   260      /**
   261       * Get the MASK for the command/ctrl key.
   262       * 
   263       * @return on OSX this returns META_MASK, else CTRL_MASK
   264       * @since 0.6
   265       */
   266      public static int getCtrlMask() {
                 /* 
    P/P           *  Method: int getCtrlMask()
                  * 
                  *  Postconditions:
                  *    return_value == One-of{4, 2}
                  *    return_value in {2, 4}
                  */
   267          return Apple.isAppleUI() ? KeyEvent.META_MASK : KeyEvent.CTRL_MASK;
   268      }
   269      
   270      /**
   271       * Check if the command/ctrl key is pressed down.
   272       * 
   273       * @param e The KeyEvent to check
   274       * @return on OSX this returns e.isMetaDown(), else e.isControlDown()
   275       * @since 0.6
   276       */
   277      public static boolean isCtrlDown(final KeyEvent e) {
                 /* 
    P/P           *  Method: bool isCtrlDown(KeyEvent)
                  * 
                  *  Preconditions:
                  *    e != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   278          return Apple.isAppleUI() ? e.isMetaDown() : e.isControlDown();
   279      }
   280      
   281      /**
   282       * Clips a string if its longer than the specified width.
   283       * 
   284       * @param component Component containing string
   285       * @param string String to check
   286       * @param avaiableWidth Available Width
   287       * 
   288       * @return String (clipped if required)
   289       */
   290      public static String clipStringifNeeded(final JComponent component, 
   291              final String string, final int avaiableWidth) {
                 /* 
    P/P           *  Method: String clipStringifNeeded(JComponent, String, int)
                  * 
                  *  Preconditions:
                  *    (soft) component != null
                  * 
                  *  Postconditions:
                  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                  *    return_value == One-of{&amp;"", &amp;java.lang.StringBuilder:toString(...), string}
                  *    return_value != null
                  * 
                  *  Test Vectors:
                  *    string: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:equals(...)@292: {0}, {1}
                  */
   292          if ((string == null) || (string.equals(""))) {
   293              return "";
   294          }
   295          final FontMetrics fm = component.getFontMetrics(component.getFont());
   296          final int width = SwingUtilities.computeStringWidth(fm, string);
   297          if (width > avaiableWidth) {
   298               return clipString(component, string, avaiableWidth);
   299           }
   300          return string;
   301      }
   302       /**
   303       * Clips the passed string .
   304       * 
   305       * @param component Component containing string
   306       * @param string String to check
   307       * @param avaiableWidth Available Width
   308       * 
   309       * @return String (clipped if required)
   310       */
   311      public static String clipString(final JComponent component, 
   312              final String string, final int avaiableWidth) {
                 /* 
    P/P           *  Method: String clipString(JComponent, String, int)
                  * 
                  *  Preconditions:
                  *    (soft) component != null
                  * 
                  *  Presumptions:
                  *    javax.swing.JComponent:getFontMetrics(...)@316 != null
                  * 
                  *  Postconditions:
                  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                  *    return_value in Addr_Set{&amp;"",&amp;java.lang.StringBuilder:toString(...)}
                  * 
                  *  Test Vectors:
                  *    string: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:equals(...)@313: {0}, {1}
                  */
   313          if ((string == null) || (string.equals(""))) {
   314              return "";
   315          }
   316          final FontMetrics fm = component.getFontMetrics(component.getFont());
   317          final String clipString = "...";
   318          int width = SwingUtilities.computeStringWidth(fm, clipString);
   319          
   320           int nChars = 0;
   321           for(int max = string.length(); nChars < max; nChars++) {
   322               width += fm.charWidth(string.charAt(nChars));
   323               if (width > avaiableWidth) {
   324                   break;
   325               }
   326           }
   327           return string.substring(0, nChars) + clipString;
   328      }
   329  
   330  }








SofCheck Inspector Build Version : 2.17854
UIUtilities.java 2009-Jun-25 01:54:24
UIUtilities.class 2009-Sep-02 17:04:15