001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002 *
003 * Copyright 2000-2013, 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 /** Width of text box for search text. */
092 private static final int SEARCH_TEXT_BOX_WIDTH = 500;
093
094 /**
095 * Hidden constructor.
096 */
097 private GuiHelper() {
098 // nothing to do
099 }
100
101 /**
102 * Configures the user interface; requests Swing settings and JGoodies Looks
103 * options from the launcher.
104 *
105 * @param options Set these options.
106 */
107 public static void configureUI(final GuiOptions options) {
108 UIManager.put("ClassLoader", CLASS.getClassLoader());
109
110 Options.setDefaultIconSize(new Dimension(18, 18));
111 Options.setUseNarrowButtons(options.isUseNarrowButtons());
112 Options.setTabIconsEnabled(options.isTabIconsEnabled());
113 UIManager.put(Options.POPUP_DROP_SHADOW_ENABLED_KEY, options
114 .isPopupDropShadowEnabled());
115 // LATER m31 20100319: we make this now direct in QedeqPane, this line
116 // didn't help. Why?
117 // we want our disabled TextAreas to look same if not editable
118 UIManager.put("TextArea.disabledBackground", UIManager
119 .get("TextArea.background"));
120
121 UIManager.put("ToolTip.font",
122 new FontUIResource("Lucida Sans Unicode", Font.PLAIN,
123 UIManager.getFont("ToolTip.font").getSize()));
124
125 // Swing Settings
126 LookAndFeel selectedLaf = options.getSelectedLookAndFeel();
127 if (selectedLaf instanceof PlasticLookAndFeel) {
128 PlasticLookAndFeel.setPlasticTheme(options.getSelectedTheme());
129 PlasticLookAndFeel.setTabStyle(options.getPlasticTabStyle());
130 PlasticLookAndFeel.setHighContrastFocusColorsEnabled(options
131 .isPlasticHighContrastFocusEnabled());
132 } else if (selectedLaf.getClass() == MetalLookAndFeel.class) {
133 MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
134 }
135
136 // Work around caching in MetalRadioButtonUI
137 JRadioButton radio = new JRadioButton();
138 radio.getUI().uninstallUI(radio);
139 JCheckBox checkBox = new JCheckBox();
140 checkBox.getUI().uninstallUI(checkBox);
141
142 try {
143 UIManager.setLookAndFeel(selectedLaf);
144 } catch (Exception e) {
145 Trace.trace(CLASS, "configureUI", "Can't change L&F", e);
146 }
147
148 }
149
150 /**
151 * Creates a JButton configured for use in a JToolBar.
152 *
153 * @param iconName Name of icon.
154 * @param toolTipText Tool tip text.
155 * @return Button.
156 */
157 public static AbstractButton createToolBarButton(final String iconName,
158 final String toolTipText) {
159 final JButton button = new JButton(GuiHelper.readImageIcon(iconName));
160 button.setToolTipText(toolTipText);
161 button.setFocusable(false);
162 return button;
163 }
164
165 /**
166 * Creates a JButton configured for use in a JToolBar.
167 *
168 * @param iconName Name of icon.
169 * @param toolTipText Tool tip text.
170 * @param action Action for this button.
171 * @param keyStroke Short cut key.
172 * @return Button.
173 */
174 public static AbstractButton createToolBarButton(final String iconName,
175 final String toolTipText, final ActionListener action,
176 final KeyStroke keyStroke) {
177 AbstractButton button = createToolBarButton(iconName, toolTipText);
178 button.registerKeyboardAction(action, keyStroke,
179 JComponent.WHEN_IN_FOCUSED_WINDOW);
180 return button;
181 }
182
183 /**
184 * Creates a JToggleButton configured for use in a JToolBar.
185 *
186 * @param iconName Name of icon.
187 * @param toolTipText Tool tip text.
188 * @return Radio button.
189 */
190 public static AbstractButton createToolBarRadioButton(
191 final String iconName, final String toolTipText) {
192 final JToggleButton button = new JToggleButton(GuiHelper
193 .readImageIcon(iconName));
194 button.setToolTipText(toolTipText);
195 button.setFocusable(false);
196 return button;
197 }
198
199 /**
200 * Get an icon for given filename postfix.
201 *
202 * @param filename Look for this icon.
203 * @return Icon.
204 */
205 public static ImageIcon readImageIcon(final String filename) {
206 final URL url = ResourceLoaderUtility.getResourceUrl("images/" + filename);
207 if (url == null) {
208 Trace.fatal(CLASS, "readImageIcon", "image icon not found: images/" + filename,
209 new RuntimeException());
210 return null;
211 }
212 return new ImageIcon(url);
213 }
214
215 /**
216 * Get background color for highlighting the current line.
217 *
218 * @return Background color.
219 */
220 public static Color getLineHighlighterBackgroundColor() {
221 return lineHighlighterBackgroundColor;
222 }
223
224 /**
225 * Get background color for error text areas.
226 *
227 * @return Background color.
228 */
229 public static Color getErrorTextBackgroundColor() {
230 return errorTextBackgroundColor;
231 }
232
233 /**
234 * Get background color for warning text areas.
235 *
236 * @return Background color.
237 */
238 public static Color getWarningTextBackgroundColor() {
239 return warningTextBackgroundColor;
240 }
241
242 /**
243 * Get background color for marked and highlightted text areas.
244 *
245 * @return Background color.
246 */
247 public static Color getCurrentAndMarkedBackgroundColor() {
248 return markedAndHiglightedBackgroundColor;
249 }
250
251 /**
252 * Paint current line background area with
253 * {@link #getLineHighlighterBackgroundColor()}.
254 *
255 * @param g Graphics to use.
256 * @param c Text component to work on.
257 * @param col Color to work with.
258 */
259 public static void paintCurrentLineBackground(final Graphics g,
260 final JTextComponent c, final Color col) {
261 // if something is selected we don't highlight
262 if (c.getSelectionStart() != c.getSelectionEnd()) {
263 return;
264 }
265 Rectangle r;
266 try {
267 r = c.modelToView(c.getCaretPosition());
268 } catch (BadLocationException couldNotHappen) {
269 throw new RuntimeException(couldNotHappen);
270 }
271 g.setColor(col);
272 g.fillRect(0, r.y, c.getWidth(), r.height);
273 }
274
275 /**
276 * Adds boarder space and floats panel to the right.
277 *
278 * @param panel Panel to decorate.
279 * @return Panel with more decorations.
280 */
281 public static JComponent addSpaceAndAlignRight(final JPanel panel) {
282 JPanel withSpace = new JPanel();
283 withSpace.add(panel);
284 JPanel alignRight = new JPanel();
285 alignRight.setLayout(new FlowLayout(FlowLayout.RIGHT));
286 alignRight.add(withSpace);
287 return alignRight;
288 }
289
290 /**
291 * Adds boarder space and floats panel to the left.
292 *
293 * @param panel Panel to decorate.
294 * @return Panel with more decorations.
295 */
296 public static JComponent alignLeft(final JPanel panel) {
297 JPanel withSpace = new JPanel();
298 withSpace.add(panel);
299 JPanel alignLeft = new JPanel();
300 alignLeft.setLayout(new FlowLayout(FlowLayout.LEFT));
301 alignLeft.add(withSpace);
302 return alignLeft;
303 }
304
305 /**
306 * Width of horizontal empty border.
307 *
308 * @return Return horizontal empty boarder pixel distance.
309 */
310 public static int getEmptyBoderPixelsX() {
311 return DEFAULT_EMPTY_BORDER_PIXEL_X;
312 }
313
314 /**
315 * Width of vertical empty border.
316 *
317 * @return Return vertical empty boarder pixel distance.
318 */
319 public static int getEmptyBorderPixelsY() {
320 return DEFAULT_EMPTY_BORDER_PIXEL_Y;
321 }
322
323 /**
324 * A border that puts extra pixels at the sides and bottom of each pane.
325 *
326 * @return Border with extra space.
327 */
328 public static Border getEmptyBorder() {
329 return BorderFactory.createEmptyBorder(GuiHelper
330 .getEmptyBorderPixelsY(), GuiHelper.getEmptyBoderPixelsX(),
331 GuiHelper.getEmptyBorderPixelsY(), GuiHelper.getEmptyBoderPixelsX());
332 }
333
334 /**
335 * A border that puts extra pixels at the sides and bottom of each pane.
336 *
337 * @return Border with extra space.
338 */
339 public static Border getEmptyBorderStackable() {
340 return BorderFactory.createEmptyBorder(GuiHelper
341 .getEmptyBorderPixelsY() / 2, GuiHelper.getEmptyBoderPixelsX(),
342 GuiHelper.getEmptyBorderPixelsY() / 2, GuiHelper.getEmptyBoderPixelsX());
343 }
344
345 /**
346 * Calculate table column width according to contents. See
347 * <a href="http://www.chka.de/swing/table/cell-sizes.html">cell-sizes.html</a>
348 * (calculating initial column widths based on contents).
349 *
350 * @author Christian Kaufhold
351 *
352 * @param table Calculate width for this table and update column width values.
353 */
354 public static void calcColumnWidths(final JTable table) {
355 final JTableHeader header = table.getTableHeader();
356 TableCellRenderer defaultHeaderRenderer = null;
357 if (header != null) {
358 defaultHeaderRenderer = header.getDefaultRenderer();
359 }
360 TableColumnModel columns = table.getColumnModel();
361 TableModel data = table.getModel();
362 int margin = columns.getColumnMargin(); // only JDK1.3
363 int rowCount = data.getRowCount();
364 int totalWidth = 0;
365 for (int i = columns.getColumnCount() - 1; i >= 0; --i) {
366 final TableColumn column = columns.getColumn(i);
367 final int columnIndex = column.getModelIndex();
368 int width = -1;
369 TableCellRenderer h = column.getHeaderRenderer();
370 if (h == null) {
371 h = defaultHeaderRenderer;
372 }
373 if (h != null) { // Not explicitly impossible
374 Component c = h.getTableCellRendererComponent(table, column.getHeaderValue(),
375 false, false, -1, i);
376 width = c.getPreferredSize().width;
377 }
378 for (int row = rowCount - 1; row >= 0; --row) {
379 TableCellRenderer r = table.getCellRenderer(row, i);
380 Component c = r.getTableCellRendererComponent(table, data.getValueAt(row,
381 columnIndex), false, false, row, i);
382 width = Math.max(width, c.getPreferredSize().width);
383 }
384 if (width >= 0) {
385 column.setPreferredWidth(width + margin);
386 } else {
387 // ???
388 }
389 totalWidth += column.getPreferredWidth();
390 }
391 }
392
393 /**
394 * Width for text search box.
395 *
396 * @return Width for text search box.
397 */
398 public static int getSearchTextBoxWidth() {
399 return SEARCH_TEXT_BOX_WIDTH;
400 }
401
402 public static JComponent addSpaceAndTitle(final JPanel panel, final String title) {
403 JPanel withSpace = new JPanel();
404 withSpace.setBorder(getEmptyBorderStackable());
405 withSpace.add(panel);
406 withSpace.setLayout(new GridLayout(0, 1));
407 JPanel withTitle = new JPanel();
408 withTitle.setBorder(BorderFactory.createTitledBorder(title));
409 withTitle.add(withSpace);
410 withTitle.setLayout(new GridLayout(0, 1));
411 return withTitle;
412 }
413
414 }
|