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{&"", &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{&"",&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 |