001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002 *
003 * Copyright 2000-2011, Michael Meyling <mime@qedeq.org>.
004 *
005 * "Hilbert II" is free software; you can redistribute
006 * it and/or modify it under the terms of the GNU General Public
007 * License as published by the Free Software Foundation; either
008 * version 2 of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 */
015
016 package org.qedeq.gui.se.util;
017
018 import java.awt.Color;
019 import java.awt.Component;
020 import java.awt.Dimension;
021 import java.awt.FlowLayout;
022 import java.awt.Font;
023 import java.awt.Graphics;
024 import java.awt.GridLayout;
025 import java.awt.Rectangle;
026 import java.awt.event.ActionListener;
027 import java.net.URL;
028
029 import javax.swing.AbstractButton;
030 import javax.swing.BorderFactory;
031 import javax.swing.ImageIcon;
032 import javax.swing.JButton;
033 import javax.swing.JCheckBox;
034 import javax.swing.JComponent;
035 import javax.swing.JPanel;
036 import javax.swing.JRadioButton;
037 import javax.swing.JTable;
038 import javax.swing.JToggleButton;
039 import javax.swing.KeyStroke;
040 import javax.swing.LookAndFeel;
041 import javax.swing.UIManager;
042 import javax.swing.border.Border;
043 import javax.swing.plaf.FontUIResource;
044 import javax.swing.plaf.metal.DefaultMetalTheme;
045 import javax.swing.plaf.metal.MetalLookAndFeel;
046 import javax.swing.table.JTableHeader;
047 import javax.swing.table.TableCellRenderer;
048 import javax.swing.table.TableColumn;
049 import javax.swing.table.TableColumnModel;
050 import javax.swing.table.TableModel;
051 import javax.swing.text.BadLocationException;
052 import javax.swing.text.JTextComponent;
053
054 import org.qedeq.base.io.ResourceLoaderUtility;
055 import org.qedeq.base.trace.Trace;
056 import org.qedeq.gui.se.main.GuiOptions;
057
058 import com.jgoodies.looks.Options;
059 import com.jgoodies.looks.plastic.PlasticLookAndFeel;
060
061 /**
062 * Various GUI utility methods.
063 *
064 * @author Michael Meyling
065 */
066 public final class GuiHelper {
067
068 /** This class. */
069 private static final Class CLASS = GuiHelper.class;
070
071 /** Color for line highlighter. */
072 private static Color lineHighlighterBackgroundColor = new Color(232, 242,
073 254);
074
075 /** Color for line highlighter and marked areas. */
076 private static Color markedAndHiglightedBackgroundColor = new Color(232,
077 242, 254, 128);
078
079 /** Color for error text areas. */
080 private static Color errorTextBackgroundColor = new Color(180, 206, 255);
081
082 /** Color for warning text areas. */
083 private static Color warningTextBackgroundColor = new Color(255, 255, 190);
084
085 /** Width of empty border. */
086 private static final int DEFAULT_EMPTY_BORDER_PIXEL_X = 10;
087
088 /** Width of empty border. */
089 private static final int DEFAULT_EMPTY_BORDER_PIXEL_Y = 10;
090
091 /**
092 * Hidden constructor.
093 */
094 private GuiHelper() {
095 // nothing to do
096 }
097
098 /**
099 * Configures the user interface; requests Swing settings and JGoodies Looks
100 * options from the launcher.
101 *
102 * @param options Set these options.
103 */
104 public static void configureUI(final GuiOptions options) {
105 UIManager.put("ClassLoader", CLASS.getClassLoader());
106
107 Options.setDefaultIconSize(new Dimension(18, 18));
108 Options.setUseNarrowButtons(options.isUseNarrowButtons());
109 Options.setTabIconsEnabled(options.isTabIconsEnabled());
110 UIManager.put(Options.POPUP_DROP_SHADOW_ENABLED_KEY, options
111 .isPopupDropShadowEnabled());
112 // LATER m31 20100319: we make this now direct in QedeqPane, this line
113 // didn't help. Why?
114 // we want our disabled TextAreas to look same if not editable
115 UIManager.put("TextArea.disabledBackground", UIManager
116 .get("TextArea.background"));
117
118 UIManager.put("ToolTip.font",
119 new FontUIResource("Lucida Sans Unicode", Font.PLAIN,
120 UIManager.getFont("ToolTip.font").getSize()));
121
122 // Swing Settings
123 LookAndFeel selectedLaf = options.getSelectedLookAndFeel();
124 if (selectedLaf instanceof PlasticLookAndFeel) {
125 PlasticLookAndFeel.setPlasticTheme(options.getSelectedTheme());
126 PlasticLookAndFeel.setTabStyle(options.getPlasticTabStyle());
127 PlasticLookAndFeel.setHighContrastFocusColorsEnabled(options
128 .isPlasticHighContrastFocusEnabled());
129 } else if (selectedLaf.getClass() == MetalLookAndFeel.class) {
130 MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
131 }
132
133 // Work around caching in MetalRadioButtonUI
134 JRadioButton radio = new JRadioButton();
135 radio.getUI().uninstallUI(radio);
136 JCheckBox checkBox = new JCheckBox();
137 checkBox.getUI().uninstallUI(checkBox);
138
139 try {
140 UIManager.setLookAndFeel(selectedLaf);
141 } catch (Exception e) {
142 Trace.trace(CLASS, "configureUI", "Can't change L&F", e);
143 }
144
145 }
146
147 /**
148 * Creates a JButton configured for use in a JToolBar.
149 *
150 * @param iconName Name of icon.
151 * @param toolTipText Tool tip text.
152 * @return Button.
153 */
154 public static AbstractButton createToolBarButton(final String iconName,
155 final String toolTipText) {
156 final JButton button = new JButton(GuiHelper.readImageIcon(iconName));
157 button.setToolTipText(toolTipText);
158 button.setFocusable(false);
159 return button;
160 }
161
162 /**
163 * Creates a JButton configured for use in a JToolBar.
164 *
165 * @param iconName Name of icon.
166 * @param toolTipText Tool tip text.
167 * @param action Action for this button.
168 * @param keyStroke Short cut key.
169 * @return Button.
170 */
171 public static AbstractButton createToolBarButton(final String iconName,
172 final String toolTipText, final ActionListener action,
173 final KeyStroke keyStroke) {
174 AbstractButton button = createToolBarButton(iconName, toolTipText);
175 button.registerKeyboardAction(action, keyStroke,
176 JComponent.WHEN_IN_FOCUSED_WINDOW);
177 return button;
178 }
179
180 /**
181 * Creates a JToggleButton configured for use in a JToolBar.
182 *
183 * @param iconName Name of icon.
184 * @param toolTipText Tool tip text.
185 * @return Radio button.
186 */
187 public static AbstractButton createToolBarRadioButton(
188 final String iconName, final String toolTipText) {
189 final JToggleButton button = new JToggleButton(GuiHelper
190 .readImageIcon(iconName));
191 button.setToolTipText(toolTipText);
192 button.setFocusable(false);
193 return button;
194 }
195
196 /**
197 * Get an icon for given filename postfix.
198 *
199 * @param filename Look for this icon.
200 * @return Icon.
201 */
202 public static ImageIcon readImageIcon(final String filename) {
203 final URL url = ResourceLoaderUtility.getResourceUrl("images/" + filename);
204 if (url == null) {
205 Trace.fatal(CLASS, "readImageIcon", "image icon not found: images/" + filename,
206 new RuntimeException());
207 return null;
208 }
209 return new ImageIcon(url);
210 }
211
212 /**
213 * Get background color for highlighting the current line.
214 *
215 * @return Background color.
216 */
217 public static Color getLineHighlighterBackgroundColor() {
218 return lineHighlighterBackgroundColor;
219 }
220
221 /**
222 * Get background color for error text areas.
223 *
224 * @return Background color.
225 */
226 public static Color getErrorTextBackgroundColor() {
227 return errorTextBackgroundColor;
228 }
229
230 /**
231 * Get background color for warning text areas.
232 *
233 * @return Background color.
234 */
235 public static Color getWarningTextBackgroundColor() {
236 return warningTextBackgroundColor;
237 }
238
239 /**
240 * Get background color for marked and highlightted text areas.
241 *
242 * @return Background color.
243 */
244 public static Color getCurrentAndMarkedBackgroundColor() {
245 return markedAndHiglightedBackgroundColor;
246 }
247
248 /**
249 * Paint current line background area with
250 * {@link #getLineHighlighterBackgroundColor()}.
251 *
252 * @param g Graphics to use.
253 * @param c Text component to work on.
254 * @param col Color to work with.
255 */
256 public static void paintCurrentLineBackground(final Graphics g,
257 final JTextComponent c, final Color col) {
258 // if something is selected we don't highlight
259 if (c.getSelectionStart() != c.getSelectionEnd()) {
260 return;
261 }
262 Rectangle r;
263 try {
264 r = c.modelToView(c.getCaretPosition());
265 } catch (BadLocationException couldNotHappen) {
266 throw new RuntimeException(couldNotHappen);
267 }
268 g.setColor(col);
269 g.fillRect(0, r.y, c.getWidth(), r.height);
270 }
271
272 /**
273 * Adds boarder space and floats panel to the right.
274 *
275 * @param panel Panel to decorate.
276 * @return Panel with more decorations.
277 */
278 public static JComponent addSpaceAndAlignRight(final JPanel panel) {
279 JPanel withSpace = new JPanel();
280 withSpace.add(panel);
281 JPanel alignRight = new JPanel();
282 alignRight.setLayout(new FlowLayout(FlowLayout.RIGHT));
283 alignRight.add(withSpace);
284 return alignRight;
285 }
286
287 /**
288 * Width of horizontal empty border.
289 *
290 * @return Return horizontal empty boarder pixel distance.
291 */
292 public static int getEmptyBoderPixelsX() {
293 return DEFAULT_EMPTY_BORDER_PIXEL_X;
294 }
295
296 /**
297 * Width of vertical empty border.
298 *
299 * @return Return vertical empty boarder pixel distance.
300 */
301 public static int getEmptyBorderPixelsY() {
302 return DEFAULT_EMPTY_BORDER_PIXEL_Y;
303 }
304
305 /**
306 * A border that puts extra pixels at the sides and bottom of each pane.
307 *
308 * @return Border with extra space.
309 */
310 public static Border getEmptyBorder() {
311 return BorderFactory.createEmptyBorder(GuiHelper
312 .getEmptyBorderPixelsY(), GuiHelper.getEmptyBoderPixelsX(),
313 GuiHelper.getEmptyBorderPixelsY(), GuiHelper.getEmptyBoderPixelsX());
314 }
315
316 /**
317 * A border that puts extra pixels at the sides and bottom of each pane.
318 *
319 * @return Border with extra space.
320 */
321 public static Border getEmptyBorderStackable() {
322 return BorderFactory.createEmptyBorder(GuiHelper
323 .getEmptyBorderPixelsY() / 2, GuiHelper.getEmptyBoderPixelsX(),
324 GuiHelper.getEmptyBorderPixelsY() / 2, GuiHelper.getEmptyBoderPixelsX());
325 }
326
327 /**
328 * Calculate table column width according to contents. See
329 * <a href="http://www.chka.de/swing/table/cell-sizes.html">cell-sizes.html</a>
330 * (calculating initial column widths based on contents).
331 *
332 * @author Christian Kaufhold
333 *
334 * @param table Calculate width for this table and update column width values.
335 */
336 public static void calcColumnWidths(final JTable table) {
337 final JTableHeader header = table.getTableHeader();
338 TableCellRenderer defaultHeaderRenderer = null;
339 if (header != null) {
340 defaultHeaderRenderer = header.getDefaultRenderer();
341 }
342 TableColumnModel columns = table.getColumnModel();
343 TableModel data = table.getModel();
344 int margin = columns.getColumnMargin(); // only JDK1.3
345 int rowCount = data.getRowCount();
346 int totalWidth = 0;
347 for (int i = columns.getColumnCount() - 1; i >= 0; --i) {
348 final TableColumn column = columns.getColumn(i);
349 final int columnIndex = column.getModelIndex();
350 int width = -1;
351 TableCellRenderer h = column.getHeaderRenderer();
352 if (h == null) {
353 h = defaultHeaderRenderer;
354 }
355 if (h != null) { // Not explicitly impossible
356 Component c = h.getTableCellRendererComponent(table, column.getHeaderValue(),
357 false, false, -1, i);
358 width = c.getPreferredSize().width;
359 }
360 for (int row = rowCount - 1; row >= 0; --row) {
361 TableCellRenderer r = table.getCellRenderer(row, i);
362 Component c = r.getTableCellRendererComponent(table, data.getValueAt(row,
363 columnIndex), false, false, row, i);
364 width = Math.max(width, c.getPreferredSize().width);
365 }
366 if (width >= 0) {
367 column.setPreferredWidth(width + margin);
368 } else {
369 // ???
370 }
371 totalWidth += column.getPreferredWidth();
372 }
373 }
374
375 public static JComponent addSpaceAndTitle(final JPanel panel, final String title) {
376 JPanel withSpace = new JPanel();
377 withSpace.setBorder(getEmptyBorderStackable());
378 withSpace.add(panel);
379 withSpace.setLayout(new GridLayout(0, 1));
380 JPanel withTitle = new JPanel();
381 withTitle.setBorder(BorderFactory.createTitledBorder(title));
382 withTitle.add(withSpace);
383 withTitle.setLayout(new GridLayout(0, 1));
384 return withTitle;
385 }
386
387 }
|