content: /**
   * Copyright 2020 Alexander Herzog
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package tools;
  
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.Dimension;
  import java.awt.FlowLayout;
  import java.awt.event.ActionListener;
  import java.awt.image.BufferedImage;
  import java.io.Serializable;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import javax.swing.BorderFactory;
  import javax.swing.Icon;
  import javax.swing.ImageIcon;
  import javax.swing.JButton;
  import javax.swing.JLabel;
  import javax.swing.JPanel;
  import javax.swing.JToolBar;
  import javax.swing.SwingConstants;
  import javax.swing.UIManager;
  import javax.swing.table.AbstractTableModel;
  
  import ui.tools.FlatLaFHelper;
  
  /**
   * Stellt gegenber dem {@link AbstractTableModel} einige Funktionen bereit,
   * um {@link JPanel}-basierende Zellen zu erzeugen, die durch {@link JTableExt}
   * angezeigt werden knnen.
   * @see JTableExt
   * @author Alexander Herzog
   * @version 1.4
   */
  public abstract class JTableExtAbstractTableModel extends AbstractTableModel {
  	/**
  	 * Serialisierungs-ID der Klasse
  	 * @see Serializable
  	 */
  	private static final long serialVersionUID = -4249212671820906541L;
  
  	/**
  	 * Konstruktor der Klasse
  	 */
  	public JTableExtAbstractTableModel() {
  		/*
  		 * Wird nur bentigt, um einen JavaDoc-Kommentar fr diesen (impliziten) Konstruktor
  		 * setzen zu knnen, damit der JavaDoc-Compiler keine Warnung mehr ausgibt.
  		 */
  	}
  
  	/**
  	 * Hintergrundfarbe fr einzelne Tabellenzellen
  	 * @see #getCellBackgroundColor()
  	 */
  	private Color cellBackgroundColor;
  
  	/**
  	 * Liefert die Hintergrundfarbe fr die einzelnen Tabellenzellen.
  	 * @return	Hintergrundfarbe fr einzelne Tabellenzellen
  	 */
  	protected Color getCellBackgroundColor() {
  		if (cellBackgroundColor==null) cellBackgroundColor=UIManager.getColor("Table.background");
  		return cellBackgroundColor;
  	}
  
  	/**
  	 * Erstellt ein Panel fr eine Tabellenzelle aus mehreren Schaltflchen
  	 * @param title	Namen der Schaltflchen (darf <code>null</code> sein)
  	 * @param iconURL	Icons fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param listener	Listener die beim Anklicken der Schaltflchen ausgelst werden
  	 * @return	Panel welches die angegebenen Schaltflchen enthlt
  	 */
  	protected final JPanel makeButtonPanel(final String[] title, final URL[] iconURL, final ActionListener[] listener) {
  		String[] tooltip=new String[title.length];
  		return makeButtonPanel(title,tooltip,iconURL,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel fr eine Tabellenzelle aus mehreren Schaltflchen
  	 * @param title	Namen der Schaltflchen (darf <code>null</code> sein)
  	 * @param icons	Icons fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param listener	Listener die beim Anklicken der Schaltflchen ausgelst werden
  	 * @return	Panel welches die angegebenen Schaltflchen enthlt
  	 */
  	protected final JPanel makeButtonPanel(final String[] title, final Icon[] icons, final ActionListener[] listener) {
  		String[] tooltip=new String[title.length];
  		return makeButtonPanel(title,tooltip,icons,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel fr eine Tabellenzelle aus mehreren Schaltflchen
  	 * @param title	Namen der Schaltflchen (darf <code>null</code> sein)
  	 * @param tooltip	Tooltips fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param iconURL	Icons fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param listener	Listener die beim Anklicken der Schaltflchen ausgelst werden
  	 * @return	Panel welches die angegebenen Schaltflchen enthlt
  	 */
  	protected final JPanel makeButtonPanel(String[] title, String[] tooltip, URL[] iconURL, ActionListener[] listener) {
  		if (title==null) title=new String[0];
  		if (tooltip==null) tooltip=new String[0];
  		if (iconURL==null) iconURL=new URL[0];
  		if (listener==null) listener=new ActionListener[0];
  		int max=title.length;
  		max=Math.max(max,tooltip.length);
  		max=Math.max(max,iconURL.length);
  		max=Math.max(max,listener.length);
  		for (int i=1;i<=max;i++) {
  			if (title.length<i) {List<String> l=new ArrayList<>(Arrays.asList(title)); l.add(null); title=l.toArray(String[]::new);}
  			if (tooltip.length<i) {List<String> l=new ArrayList<>(Arrays.asList(tooltip)); l.add(null); tooltip=l.toArray(String[]::new);}
  			if (iconURL.length<i) {List<URL> l=new ArrayList<>(Arrays.asList(iconURL)); l.add(null); iconURL=l.toArray(URL[]::new);}
  			if (listener.length<i) {List<ActionListener> l=new ArrayList<>(Arrays.asList(listener)); l.add(null); listener=l.toArray(ActionListener[]::new);}
  		}
  
  		final JPanel p=new JPanel(new BorderLayout());
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JToolBar toolbar=new JToolBar(SwingConstants.HORIZONTAL);
  		if (FlatLaFHelper.isActive()) {
  			toolbar.setOpaque(false);
  		} else {
  			toolbar.setBackground(getCellBackgroundColor());
  		}
  		toolbar.setFloatable(false);
  		p.add(toolbar,BorderLayout.CENTER);
  		p.setBorder(BorderFactory.createEmptyBorder());
  		for (int i=0;i<Math.min(title.length,Math.min(tooltip.length,Math.min(iconURL.length,listener.length)));i++) {
  			final JButton button;
  			if (iconURL[i]==null) {
  				if (title[i]==null || title[i].isEmpty()) title[i]="-";
  				button=new JButton(title[i]);
  			} else {
  				if (title[i]==null || title[i].isEmpty()) button=new JButton(new ImageIcon(iconURL[i])); else button=new JButton(title[i],new ImageIcon(iconURL[i]));
  			}
  			button.setBackground(getCellBackgroundColor());
  			button.addActionListener(listener[i]);
  			if (tooltip[i]!=null && !tooltip[i].isEmpty()) {
  				button.setToolTipText(tooltip[i]);
  			}
  			toolbar.add(button);
  		}
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel fr eine Tabellenzelle aus mehreren Schaltflchen
  	 * @param title	Namen der Schaltflchen (darf <code>null</code> sein)
  	 * @param tooltip	Tooltips fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param icons	Icons fr die Schaltflchen (darf <code>null</code> sein)
  	 * @param listener	Listener die beim Anklicken der Schaltflchen ausgelst werden
  	 * @return	Panel welches die angegebenen Schaltflchen enthlt
  	 */
  	protected final JPanel makeButtonPanel(String[] title, String[] tooltip, Icon[] icons, ActionListener[] listener) {
  		if (title==null) title=new String[0];
  		if (tooltip==null) tooltip=new String[0];
  		if (icons==null) icons=new Icon[0];
  		if (listener==null) listener=new ActionListener[0];
  		int max=title.length;
  		max=Math.max(max,tooltip.length);
  		max=Math.max(max,icons.length);
  		max=Math.max(max,listener.length);
  		for (int i=1;i<=max;i++) {
  			if (title.length<i) {List<String> l=new ArrayList<>(Arrays.asList(title)); l.add(null); title=l.toArray(String[]::new);}
  			if (tooltip.length<i) {List<String> l=new ArrayList<>(Arrays.asList(tooltip)); l.add(null); tooltip=l.toArray(String[]::new);}
  			if (icons.length<i) {List<Icon> l=new ArrayList<>(Arrays.asList(icons)); l.add(null); icons=l.toArray(Icon[]::new);}
  			if (listener.length<i) {List<ActionListener> l=new ArrayList<>(Arrays.asList(listener)); l.add(null); listener=l.toArray(ActionListener[]::new);}
  		}
  
  		final JPanel p=new JPanel(new BorderLayout());
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JToolBar toolbar=new JToolBar(SwingConstants.HORIZONTAL);
  		if (FlatLaFHelper.isActive()) {
  			toolbar.setOpaque(false);
  		} else {
  			toolbar.setBackground(getCellBackgroundColor());
  		}
  		toolbar.setFloatable(false);
  		p.add(toolbar,BorderLayout.CENTER);
  		p.setBorder(BorderFactory.createEmptyBorder());
  		for (int i=0;i<Math.min(title.length,Math.min(tooltip.length,Math.min(icons.length,listener.length)));i++) {
  			final JButton button;
  			if (icons[i]==null) {
  				if (title[i]==null || title[i].isEmpty()) title[i]="-";
  				button=new JButton(title[i]);
  			} else {
  				if (title[i]==null || title[i].isEmpty()) button=new JButton(icons[i]); else button=new JButton(title[i],icons[i]);
  			}
  			button.setBackground(getCellBackgroundColor());
  			button.addActionListener(listener[i]);
  			if (tooltip[i]!=null && !tooltip[i].isEmpty()) {
  				button.setToolTipText(tooltip[i]);
  			}
  			toolbar.add(button);
  		}
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Textpanel
  	 * @param text	Anzuzeigender Text
  	 * @param iconURL	Vor dem Text anzuzeigendes Icon (kann <code>null</code> sein)
  	 * @return	Panel welches den Text enthlt
  	 */
  	protected final JPanel makePanel(final String text, final URL iconURL) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(text);
  		if (iconURL!=null) label.setIcon(new ImageIcon(iconURL));
  		p.add(label,BorderLayout.CENTER);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Textpanel
  	 * @param text	Anzuzeigender Text
  	 * @param icon	Vor dem Text anzuzeigendes Icon (kann <code>null</code> sein)
  	 * @return	Panel welches den Text enthlt
  	 */
  	protected final JPanel makePanelIcon(final String text, final Icon icon) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(text);
  		if (icon!=null) label.setIcon(icon);
  		p.add(label,BorderLayout.CENTER);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Icon-Panel
  	 * @param image	Anzuzeigendes Bild
  	 * @return	Panel welches das Bild enthlt
  	 */
  	protected final JPanel makePanel(final BufferedImage image) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel();
  		label.setIcon(new ImageIcon(image));
  		p.add(label,BorderLayout.CENTER);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel aus einem Text und einer Schaltflche
  	 * @param title	Beschriftung
  	 * @param iconURL	Icon der Schaltflche
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanel(final String title, final URL iconURL, final ActionListener listener) {
  		return makeEditPanel(null,title,iconURL,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel aus einem Text und einer Schaltflche
  	 * @param title	Beschriftung
  	 * @param icon	Icon der Schaltflche
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanel(final String title, final Icon icon, final ActionListener listener) {
  		return makeEditPanel(null,title,icon,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel aus einem Text (mit optionalem Icon) und einer Schaltflche
  	 * @param labelIconURL	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param iconURL	Icon der Schaltflche
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanel(final URL labelIconURL, final String title, final URL iconURL, final ActionListener listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIconURL!=null) label.setIcon(new ImageIcon(labelIconURL));
  		p.add(label,BorderLayout.CENTER);
  		JButton button; p.add(button=new JButton(new ImageIcon(iconURL)),BorderLayout.EAST);
  		button.addActionListener(listener);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel aus einem Text (mit optionalem Icon) und einer Schaltflche
  	 * @param labelIconURL	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param icon	Icon der Schaltflche
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanel(final URL labelIconURL, final String title, final Icon icon, final ActionListener listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIconURL!=null) label.setIcon(new ImageIcon(labelIconURL));
  		p.add(label,BorderLayout.CENTER);
  		JButton button; p.add(button=new JButton(icon),BorderLayout.EAST);
  		button.addActionListener(listener);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text und einer Schaltflche
  	 * @param title	Beschriftung
  	 * @param iconURL	Icon der Schaltflche
  	 * @param hint	Tooltiptext fr die Schaltflche (kann <code>null</code> sein)
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final String title, final URL iconURL, final String hint, final ActionListener listener) {
  		return makeEditPanelSmallBorder(null,title,iconURL,hint,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text und einer Schaltflche
  	 * @param title	Beschriftung
  	 * @param icon	Icon der Schaltflche
  	 * @param hint	Tooltiptext fr die Schaltflche (kann <code>null</code> sein)
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final String title, final Icon icon, final String hint, final ActionListener listener) {
  		return makeEditPanelSmallBorder((URL)null,title,icon,hint,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und einer Schaltflche
  	 * @param labelIconURL	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param iconURL	Icon der Schaltflche
  	 * @param hint	Tooltiptext fr die Schaltflche (kann <code>null</code> sein)
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final URL labelIconURL, final String title, final URL iconURL, final String hint, final ActionListener listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIconURL!=null) label.setIcon(new ImageIcon(labelIconURL));
  		p.add(label,BorderLayout.CENTER);
  		JButton button; p.add(button=new JButton(new ImageIcon(iconURL)),BorderLayout.EAST);
  		if (hint!=null) button.setToolTipText(hint);
  		button.setPreferredSize(new Dimension(24,24));
  		button.addActionListener(listener);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und einer Schaltflche
  	 * @param labelIconURL	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param icon	Icon der Schaltflche
  	 * @param hint	Tooltiptext fr die Schaltflche (kann <code>null</code> sein)
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final URL labelIconURL, final String title, final Icon icon, final String hint, final ActionListener listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIconURL!=null) label.setIcon(new ImageIcon(labelIconURL));
  		p.add(label,BorderLayout.CENTER);
  		JButton button; p.add(button=new JButton(icon),BorderLayout.EAST);
  		if (hint!=null) button.setToolTipText(hint);
  		button.setPreferredSize(new Dimension(24,24));
  		button.addActionListener(listener);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und einer Schaltflche
  	 * @param labelIcon	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param icon	Icon der Schaltflche
  	 * @param hint	Tooltiptext fr die Schaltflche (kann <code>null</code> sein)
  	 * @param listener	Callback das beim Anklicken der Schaltflche aufgerufen werden soll
  	 * @return	Panel aus Text und Schaltflche
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final Icon labelIcon, final String title, final Icon icon, final String hint, final ActionListener listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIcon!=null) label.setIcon(labelIcon);
  		p.add(label,BorderLayout.CENTER);
  		JButton button; p.add(button=new JButton(icon),BorderLayout.EAST);
  		if (hint!=null) button.setToolTipText(hint);
  		button.setPreferredSize(new Dimension(24,24));
  		button.addActionListener(listener);
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text und mehreren Schaltflche
  	 * @param title	Beschriftung
  	 * @param iconURL	Icons der Schaltflchen
  	 * @param hint	Tooltiptexts fr die Schaltflchen (kann ganz oder teilweise <code>null</code> sein)
  	 * @param listener	Callbacks die beim Anklicken der Schaltflchen aufgerufen werden sollen
  	 * @return	Panel aus Text und Schaltflchen
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final String title, final URL[] iconURL, final String[] hint, final ActionListener[] listener) {
  		return makeEditPanelSmallBorder((URL)null,title,iconURL,hint,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text und mehreren Schaltflche
  	 * @param title	Beschriftung
  	 * @param icons	Icons der Schaltflchen
  	 * @param hint	Tooltiptexts fr die Schaltflchen (kann ganz oder teilweise <code>null</code> sein)
  	 * @param listener	Callbacks die beim Anklicken der Schaltflchen aufgerufen werden sollen
  	 * @return	Panel aus Text und Schaltflchen
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final String title, final Icon[] icons, final String[] hint, final ActionListener[] listener) {
  		return makeEditPanelSmallBorderIcon(null,title,icons,hint,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und mehreren Schaltflche
  	 * @param labelIconURL	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param iconURL	Icons der Schaltflchen
  	 * @param hint	Tooltiptexts fr die Schaltflchen (kann ganz oder teilweise <code>null</code> sein)
  	 * @param listener	Callbacks die beim Anklicken der Schaltflchen aufgerufen werden sollen
  	 * @return	Panel aus Text und Schaltflchen
  	 */
  	protected final JPanel makeEditPanelSmallBorder(final URL labelIconURL, final String title, final URL[] iconURL, final String[] hint, final ActionListener[] listener) {
  		return makeEditPanelSmallBorderIcon((labelIconURL!=null)?new ImageIcon(labelIconURL):null,title,iconURL,hint,listener);
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und mehreren Schaltflche
  	 * @param labelIcon	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param iconURL	Icons der Schaltflchen
  	 * @param hint	Tooltiptexts fr die Schaltflchen (kann ganz oder teilweise <code>null</code> sein)
  	 * @param listener	Callbacks die beim Anklicken der Schaltflchen aufgerufen werden sollen
  	 * @return	Panel aus Text und Schaltflchen
  	 */
  	protected final JPanel makeEditPanelSmallBorderIcon(final Icon labelIcon, final String title, final URL[] iconURL, final String[] hint, final ActionListener[] listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIcon!=null) label.setIcon(labelIcon);
  		p.add(label,BorderLayout.CENTER);
  		JButton button;
  		JPanel buttonPanel=new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));
  		buttonPanel.setBackground(new Color(255,255,255,0));
  
  		p.add(buttonPanel,BorderLayout.EAST);
  		for (int i=0;i<Math.min(iconURL.length,listener.length);i++) {
  			final Icon icon=(iconURL[i]!=null)?new ImageIcon(iconURL[i]):null;
  			buttonPanel.add(button=new JButton(icon));
  			if (hint!=null && hint.length>i && hint[i]!=null) button.setToolTipText(hint[i]);
  			button.setPreferredSize(new Dimension(24,24));
  			button.addActionListener(listener[i]);
  		}
  		return p;
  	}
  
  	/**
  	 * Erstellt ein Panel mit reduziertem Rahmenabstand aus einem Text (mit optionalem Icon) und mehreren Schaltflche
  	 * @param labelIcon	Icon fr Beschriftung (kann <code>null</code> sein)
  	 * @param title	Beschriftung
  	 * @param icons	Icons der Schaltflchen
  	 * @param hint	Tooltiptexts fr die Schaltflchen (kann ganz oder teilweise <code>null</code> sein)
  	 * @param listener	Callbacks die beim Anklicken der Schaltflchen aufgerufen werden sollen
  	 * @return	Panel aus Text und Schaltflchen
  	 */
  	protected final JPanel makeEditPanelSmallBorderIcon(final Icon labelIcon, final String title, final Icon[] icons, final String[] hint, final ActionListener[] listener) {
  		JPanel p=new JPanel(new BorderLayout());
  		p.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
  		if (FlatLaFHelper.isActive()) {
  			p.setOpaque(false);
  		} else {
  			p.setBackground(getCellBackgroundColor());
  		}
  		final JLabel label=new JLabel(title);
  		if (labelIcon!=null) label.setIcon(labelIcon);
  		p.add(label,BorderLayout.CENTER);
  		JButton button;
  		JPanel buttonPanel=new JPanel(new FlowLayout(FlowLayout.LEFT,0,0));if (FlatLaFHelper.isActive()) {
  			buttonPanel.setOpaque(false);
  		} else {
  			buttonPanel.setBackground(new Color(255,255,255,0));
  		}
  		p.add(buttonPanel,BorderLayout.EAST);
  		for (int i=0;i<Math.min(icons.length,listener.length);i++) {
  			buttonPanel.add(button=new JButton(icons[i]));
  			if (hint!=null && hint.length>i && hint[i]!=null) button.setToolTipText(hint[i]);
  			button.setPreferredSize(new Dimension(24,24));
  			button.addActionListener(listener[i]);
  		}
  		return p;
  	}
  
  	/**
  	 * Erstellt ein leeres Panel
  	 * @return	Leeres Panel
  	 */
  	protected final JPanel makeEmptyPanel() {
  		JPanel p=new JPanel(new FlowLayout(FlowLayout.LEFT));
  		p.setBorder(BorderFactory.createEmptyBorder());
  		p.setBackground(getCellBackgroundColor());
  		return p;
  	}
  }