GuiHelper.java
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(232242,
073         254);
074 
075     /** Color for line highlighter and marked areas. */
076     private static Color markedAndHiglightedBackgroundColor = new Color(232,
077         242254128);
078 
079     /** Color for error text areas. */
080     private static Color errorTextBackgroundColor = new Color(180206255);
081 
082     /** Color for warning text areas. */
083     private static Color warningTextBackgroundColor = new Color(255255190);
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(1818));
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(01));
407         JPanel withTitle = new JPanel();
408         withTitle.setBorder(BorderFactory.createTitledBorder(title));
409         withTitle.add(withSpace);
410         withTitle.setLayout(new GridLayout(01));
411         return withTitle;
412     }
413 
414 }