You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/02/19 18:04:22 UTC

[23/51] [abbrv] libraries/ compiling

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/JTableFilter.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/JTableFilter.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/JTableFilter.java
new file mode 100644
index 0000000..1e6a710
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/JTableFilter.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.table.filter;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+import javax.swing.DefaultRowSorter;
+import javax.swing.JTable;
+import javax.swing.RowFilter;
+import javax.swing.RowSorter;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+public class JTableFilter extends AbstractTableFilter<JTable> {
+
+	private static final long serialVersionUID = 1L;
+
+	private final TableRowFilter filter = new TableRowFilter();
+
+	public JTableFilter( JTable table ) {
+		super(table);
+	}
+
+	@Override
+	protected boolean execute(int col, Collection<DistinctColumnItem> items) {
+
+		RowSorter<?> rs = getTable().getRowSorter();
+
+		if (!( rs instanceof DefaultRowSorter )) return false;
+
+		DefaultRowSorter<?, ?> drs = (DefaultRowSorter<?, ?>) rs;
+
+		@SuppressWarnings("unchecked")
+		RowFilter<Object,Object> prevFilter = (RowFilter<Object, Object>) drs.getRowFilter();
+		if ( !(prevFilter instanceof TableRowFilter)) {
+			filter.setParentFilter(prevFilter);
+		}
+
+		drs.setRowFilter(filter);
+		return true;
+
+
+	}
+
+	class TableRowFilter extends RowFilter<Object,Object> implements Serializable {
+
+		private static final long serialVersionUID = 1L;
+
+		private RowFilter<Object, Object> parentFilter;
+
+		public RowFilter<Object, Object> getParentFilter() {
+			return parentFilter;
+		}
+
+		public void setParentFilter( RowFilter<Object, Object> parentFilter ) {
+			this.parentFilter = (parentFilter == null ||  parentFilter == this )? null: parentFilter;
+		}
+
+		@Override
+		public boolean include( final RowFilter.Entry<? extends Object, ? extends Object> entry) {
+
+			// use parent filter condition
+			if ( parentFilter != null && !parentFilter.include(entry)) return false;
+
+			return includeRow( new ITableFilter.Row() {
+
+				@Override
+				public Object getValue(int column) { return entry.getValue(column); }
+
+				@Override
+				public int getValueCount() { return entry.getValueCount(); }
+
+			});
+
+		}
+
+	}
+
+	public void modelChanged( TableModel model ) {
+		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>( model );
+        sorter.setSortsOnUpdates(true);
+        getTable().setRowSorter( sorter );
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableAwareCheckListRenderer.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableAwareCheckListRenderer.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableAwareCheckListRenderer.java
new file mode 100644
index 0000000..13800b6
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableAwareCheckListRenderer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package org.oxbow.swingbits.table.filter;
+
+import java.awt.Component;
+import java.lang.reflect.Method;
+
+import javax.swing.JList;
+import javax.swing.JTable;
+import javax.swing.table.TableCellRenderer;
+
+import org.oxbow.swingbits.list.CheckListRenderer;
+
+@SuppressWarnings("serial")
+public class TableAwareCheckListRenderer extends CheckListRenderer {
+	
+	private final JTable table;
+	private final int column;
+
+	public TableAwareCheckListRenderer( JTable table, int column ) {
+		this.table = table;
+		this.column = column;
+	}
+
+	@Override
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+			boolean cellHasFocus) {
+		
+		super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		
+		// try to retrieve the text from table's cell renderer
+		if (value instanceof DistinctColumnItem) {
+
+			DistinctColumnItem item = (DistinctColumnItem) value;
+			TableCellRenderer renderer = table.getCellRenderer( item.getRow(), column);
+			
+			try {
+				
+				Component cmpt = renderer.getTableCellRendererComponent(
+						table, item.getValue(), isSelected, hasFocus(), item.getRow(), column );
+
+				Method method = cmpt.getClass().getMethod("getText");
+				Object s = method.invoke(cmpt);
+				
+				if ( s instanceof String ) {
+					setText( (String)s );
+				}
+				
+			} catch (Throwable e) {
+//				e.printStackTrace();
+			}
+			
+		}
+		return this;
+		
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterColumnPopup.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterColumnPopup.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterColumnPopup.java
new file mode 100644
index 0000000..996fff0
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterColumnPopup.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.table.filter;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JToolBar;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumnModel;
+
+import org.oxbow.swingbits.list.ActionCheckListModel;
+import org.oxbow.swingbits.list.CheckList;
+import org.oxbow.swingbits.list.CheckListFilterType;
+import org.oxbow.swingbits.list.DefaultCheckListModel;
+import org.oxbow.swingbits.list.ICheckListModel;
+import org.oxbow.swingbits.misc.JSearchTextField;
+import org.oxbow.swingbits.popup.PopupWindow;
+import org.oxbow.swingbits.util.CollectionUtils;
+import org.oxbow.swingbits.util.IObjectToStringTranslator;
+
+class TableFilterColumnPopup extends PopupWindow implements MouseListener {
+
+		static class ColumnAttrs {
+			public Dimension preferredSize;
+		}
+
+		private boolean enabled = false;
+
+		private final CheckList<DistinctColumnItem> filterList = new CheckList.Builder().build();
+		private final JSearchTextField searchField = new JSearchTextField();
+
+		private final Map<Integer, ColumnAttrs> colAttrs = new HashMap<Integer, ColumnAttrs>();
+	    private int mColumnIndex = -1;
+	    
+	    private final ITableFilter<?> filter;
+		private boolean searchable;
+		private IObjectToStringTranslator translator;
+		private boolean actionsVisible = true;
+		private boolean useTableRenderers = false;
+
+		public TableFilterColumnPopup( ITableFilter<?> filter ) {
+
+			super( true );
+
+			this.filter = filter;
+			filterList.getList().setVisibleRowCount(8);
+
+			setupTableHeader();
+			filter.getTable().addPropertyChangeListener( "tableHeader", new PropertyChangeListener() {
+				public void propertyChange(PropertyChangeEvent evt) {
+					setupTableHeader();
+				}}
+			);
+			filter.getTable().addPropertyChangeListener( "model", new PropertyChangeListener() {
+				public void propertyChange(PropertyChangeEvent evt) {
+					colAttrs.clear();
+				}}
+			);
+			
+			searchField.getDocument().addDocumentListener( new DocumentListener() {
+				
+				@Override
+				public void removeUpdate(DocumentEvent e) { perform(e); }
+				
+				@Override
+				public void insertUpdate(DocumentEvent e) { perform(e); }
+				
+				@Override
+				public void changedUpdate(DocumentEvent e) { perform(e);}
+				
+				private void perform(DocumentEvent e) {
+					filterList.filter(searchField.getText(), translator, CheckListFilterType.CONTAINS );
+				}
+				
+			});
+
+		}
+		
+		public void setSearchable( boolean searchable ) {
+			this.searchable = searchable;
+		}
+		
+		public void setSearchTranslator( IObjectToStringTranslator tranlsator ) {
+			this.translator = tranlsator;
+		}
+		
+		public void setActionsVisible(boolean actionsVisible) {
+			this.actionsVisible = actionsVisible;
+		}
+		
+		public void setUseTableRenderers(boolean reuseRenderers) {
+			this.useTableRenderers = reuseRenderers;
+		}
+
+		private void setupTableHeader() {
+			JTableHeader header = filter.getTable().getTableHeader();
+			if ( header != null ) header.addMouseListener( this );
+		}
+
+
+		@SuppressWarnings("serial")
+		@Override
+		protected JComponent buildContent() {
+
+			JPanel owner = new JPanel( new BorderLayout(3,3) );
+			owner.setBorder( BorderFactory.createEmptyBorder(1, 1, 1, 1));
+			owner.setPreferredSize(new Dimension(250, 150)); // default popup size
+
+			Box commands = new Box(BoxLayout.LINE_AXIS);
+			
+			JToolBar toolbar = new JToolBar();
+			toolbar.setFloatable(false);
+			toolbar.setOpaque(false);
+			toolbar.add( new PopupWindow.CommandAction(
+					"Clear all column filters", 
+					new ImageIcon(getClass().getResource("funnel_delete.png"))) {
+				@Override
+				protected boolean perform() {
+					return clearAllFilters();
+				}
+			});
+			commands.add( toolbar );
+			
+			commands.add(Box.createHorizontalGlue());
+			
+			commands.add( new JButton( new PopupWindow.CommandAction("Apply"){
+				@Override
+				protected boolean perform() {
+					return applyColumnFilter();
+				}})
+		     );
+			commands.add( Box.createHorizontalStrut(5) );
+			commands.add( new JButton( new PopupWindow.CommandAction("Cancel")));
+			commands.setBorder( BorderFactory.createEmptyBorder(3, 0, 3, 0));
+			commands.setBackground(UIManager.getColor("Panel.background"));
+			commands.setOpaque(true);
+
+			if ( searchable) {
+				owner.add( searchField, BorderLayout.NORTH );
+			}
+			owner.add( new JScrollPane( filterList.getList() ), BorderLayout.CENTER );
+			owner.add( commands, BorderLayout.SOUTH );
+
+			return owner;
+
+		}
+		
+		private boolean applyColumnFilter() {
+			Collection<DistinctColumnItem> checked = filterList.getCheckedItems();
+			ICheckListModel<DistinctColumnItem> model = filterList.getModel(); 
+			model.filter("", translator, CheckListFilterType.CONTAINS); // clear filter to get true results
+			filter.apply(mColumnIndex, checked);
+			return true;
+		}
+		
+		private boolean clearAllFilters() {
+			filter.clear();
+			return true;
+		}
+
+		public boolean isEnabled() {
+			return enabled;
+		}
+
+		public void setEnabled(boolean enabled) {
+			this.enabled = enabled;
+		}
+
+        // Popup menus are triggered differently on different platforms
+		// Therefore, isPopupTrigger should be checked in both mousePressed and mouseReleased
+		// events for for proper cross-platform functionality
+		
+		@Override
+		public void mousePressed(MouseEvent e) {
+			if ( enabled && e.isPopupTrigger() ) showFilterPopup(e);
+		}
+
+		@Override
+		public void mouseReleased(MouseEvent e) {
+			if ( enabled && e.isPopupTrigger() ) showFilterPopup(e);
+		}
+
+		private void showFilterPopup(MouseEvent e) {
+			JTableHeader header = (JTableHeader)(e.getSource());
+			TableColumnModel colModel = filter.getTable().getColumnModel();
+
+			// The index of the column whose header was clicked
+	        int vColumnIndex = colModel.getColumnIndexAtX(e.getX());
+	        if ( vColumnIndex < 0 ) return;
+
+
+	        // Determine if mouse was clicked between column heads
+	        Rectangle headerRect = filter.getTable().getTableHeader().getHeaderRect(vColumnIndex);
+	        if (vColumnIndex == 0) {
+	            headerRect.width -= 2;
+	        } else {
+	            headerRect.grow(-2, 0);
+	        }
+
+	        // Mouse was clicked between column heads
+	        if (!headerRect.contains(e.getX(), e.getY())) return;
+
+	        // restore popup's size for the column
+	        mColumnIndex = filter.getTable().convertColumnIndexToModel(vColumnIndex);
+	        setPreferredSize( getColumnAttrs(vColumnIndex).preferredSize );
+
+	        Collection<DistinctColumnItem> distinctItems = filter.getDistinctColumnItems(mColumnIndex);
+
+	        DefaultCheckListModel<DistinctColumnItem> model = new DefaultCheckListModel<DistinctColumnItem>(distinctItems);
+			filterList.setModel( actionsVisible? new ActionCheckListModel<DistinctColumnItem>( model): model);
+	        Collection<DistinctColumnItem> checked = filter.getFilterState(mColumnIndex);
+	        
+	        // replace empty checked items with full selection
+			filterList.setCheckedItems( CollectionUtils.isEmpty(checked)? distinctItems: checked);
+
+			if ( useTableRenderers ) {
+				filterList.getList().setCellRenderer( new TableAwareCheckListRenderer( filter.getTable(), vColumnIndex) );
+			}
+			
+	        // show pop-up
+			show( header, headerRect.x, header.getHeight() );
+		}
+
+		private ColumnAttrs getColumnAttrs( int column ) {
+			ColumnAttrs attrs = colAttrs.get(column);
+			if ( attrs == null ) {
+				attrs = new ColumnAttrs();
+				colAttrs.put( column, attrs);
+			}
+
+			return attrs;
+		}
+
+		
+		@Override
+		protected void beforeShow() {
+			if ( searchable ) {
+				SwingUtilities.invokeLater( new Runnable() {
+					@Override
+					public void run() {
+						searchField.setText("");
+						searchField.requestFocusInWindow();
+					}
+				});
+			}
+		}
+		
+		@Override
+		public void beforeHide() {
+			// save pop-up's dimensions before pop-up becomes hidden
+			getColumnAttrs(mColumnIndex).preferredSize = getPreferredSize();
+		}
+
+
+		@Override
+		public void mouseClicked(MouseEvent e) {}
+
+		@Override
+		public void mouseEntered(MouseEvent e) {}
+
+		@Override
+		public void mouseExited(MouseEvent e) {}
+
+
+	}
+

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterState.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterState.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterState.java
new file mode 100644
index 0000000..aec7065
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableFilterState.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.table.filter;
+
+import static org.oxbow.swingbits.util.CollectionUtils.isEmpty;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+class TableFilterState implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+	
+	// no set - filter cleared; set - some kind of filtering
+	private final Map<Integer,Set<DistinctColumnItem>> data = new HashMap<Integer,Set<DistinctColumnItem>>();
+	
+	/**
+	 * Clears filtering for specific column
+	 */
+	public void clear( int column ) {
+		data.remove(column);
+	}
+	
+	
+	/**
+	 * Clears all filtering
+	 */
+	public void clear() {
+		data.clear();
+	}
+	
+	private Set<DistinctColumnItem> prepareValueSet( int column ) {
+		Set<DistinctColumnItem> vals =  data.get(column);
+		if ( vals == null ) {
+			vals = new HashSet<DistinctColumnItem>();
+			data.put(column, vals);
+		}
+		return vals;
+	}
+	
+	
+	/**
+	 * Adds filter value for specified column 
+	 * @param column
+	 * @param value
+	 */
+	public void addValue( int column, DistinctColumnItem value ) {
+		prepareValueSet(column).add(value);
+	}
+
+	
+	/**
+	 * Adds a collection of filter values for specified column 
+	 * @param column
+	 * @param values
+	 */
+	public void addValues( int column, Collection<DistinctColumnItem> values ) {
+		prepareValueSet(column).addAll(values);
+	}
+
+	/**
+	 * Resets a collection of filter values for specified column
+	 * @param column
+	 * @param values
+	 */
+	public void setValues( int column, Collection<DistinctColumnItem> values ) {
+		data.remove(column);
+		if ( !isEmpty(values)) {
+			prepareValueSet(column).addAll(values);
+		}
+	}
+	
+	public Collection<DistinctColumnItem> getValues( int column ) {
+		Set<DistinctColumnItem> vals =  data.get(column);
+		return vals == null? Collections.<DistinctColumnItem>emptySet(): vals;
+	}
+	
+	/**
+	 * Standard test for row inclusion using current filter values
+	 * @param entry
+	 * @return true if row has to be included
+	 */
+	public boolean include( ITableFilter.Row entry ) {
+	
+		for( int col=0; col< entry.getValueCount(); col++ ) {
+			Collection<DistinctColumnItem> values = getValues(col);
+			if ( isEmpty(values) ) continue; // no filtering for this column
+			if ( !values.contains( new DistinctColumnItem( entry.getValue(col), 0))) return false;
+		}
+		return true;
+		
+	}
+	
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableRowFilterSupport.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableRowFilterSupport.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableRowFilterSupport.java
new file mode 100644
index 0000000..ad9da21
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/TableRowFilterSupport.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.table.filter;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collections;
+
+import javax.swing.JTable;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+
+import org.oxbow.swingbits.util.IObjectToStringTranslator;
+
+public final class TableRowFilterSupport {
+
+	private boolean searchable = false;
+	private IObjectToStringTranslator translator;
+	private final ITableFilter<?> filter;
+	private boolean actionsVisible = true;
+	private boolean useTableRenderers = false;
+
+	private TableRowFilterSupport( ITableFilter<?> filter ) {
+		if ( filter == null ) throw new NullPointerException();
+		//this.table = table;
+		this.filter = filter;
+	}
+
+	public static TableRowFilterSupport forTable( JTable table ) {
+		return new TableRowFilterSupport(new JTableFilter(table));
+	}
+
+	public static TableRowFilterSupport forFilter( ITableFilter<?> filter ) {
+		return new TableRowFilterSupport(filter);
+	}
+
+	/**
+	 * Additional actions visible in column filter list
+	 * @param visible
+	 * @return
+	 */
+	public TableRowFilterSupport actions( boolean visible ) {
+		this.actionsVisible = visible;
+		return this;
+	}
+
+	/**
+	 * Comlumn filter list is searchable
+	 * @param serachable
+	 * @return
+	 */
+	public TableRowFilterSupport searchable( boolean serachable) {
+		this.searchable = serachable;
+		return this;
+	}
+
+	public TableRowFilterSupport searchTransalator( IObjectToStringTranslator translator ) {
+		this.translator = translator;
+		return this;
+	}
+
+	public TableRowFilterSupport useTableRenderers( boolean value ) {
+		this.useTableRenderers = value;
+		return this;
+	}
+
+	public JTable apply() {
+
+		final TableFilterColumnPopup filterPopup = new TableFilterColumnPopup(filter);
+		filterPopup.setEnabled(true);
+		filterPopup.setActionsVisible(actionsVisible);
+		filterPopup.setSearchable(searchable);
+		filterPopup.setSearchTranslator(translator);
+		filterPopup.setUseTableRenderers( useTableRenderers );
+
+		setupTableHeader();
+
+		return filter.getTable();
+	}
+
+	private void setupTableHeader() {
+
+		final JTable table = filter.getTable();
+
+		filter.addChangeListener(new IFilterChangeListener() {
+
+			@Override
+			public void filterChanged(ITableFilter<?> filter) {
+				table.getTableHeader().repaint();
+
+			}
+		});
+
+		// make sure that search component is reset after table model changes
+		setupHeaderRenderers(table.getModel(), true );
+//		table.addPropertyChangeListener("model", new PropertyChangeListener() {
+//
+//			public void propertyChange(PropertyChangeEvent evt) {
+//
+//				FilterTableHeaderRenderer headerRenderer = new FilterTableHeaderRenderer(filter);
+//				filter.modelChanged((TableModel) evt.getNewValue());
+//
+//				for( TableColumn c:  Collections.list( filter.getTable().getColumnModel().getColumns()) ) {
+//					c.setHeaderRenderer( headerRenderer );
+//				}
+//			}}
+//
+//		);
+	}
+
+	private void setupHeaderRenderers( TableModel newModel, boolean fullSetup ) {
+
+		JTable table =  filter.getTable();
+
+		FilterTableHeaderRenderer headerRenderer = new FilterTableHeaderRenderer(filter);
+		filter.modelChanged( newModel );
+
+		for( TableColumn c:  Collections.list( table.getColumnModel().getColumns()) ) {
+			c.setHeaderRenderer( headerRenderer );
+		}
+
+		if ( !fullSetup ) return;
+
+		table.addPropertyChangeListener("model", new PropertyChangeListener() {
+
+			public void propertyChange(PropertyChangeEvent e) {
+				setupHeaderRenderers( (TableModel) e.getNewValue(), false );
+			}
+
+		});
+
+
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel.png
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel.png b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel.png
new file mode 100644
index 0000000..dd8344c
Binary files /dev/null and b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel.png differ

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel_delete.png
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel_delete.png b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel_delete.png
new file mode 100644
index 0000000..f801e4d
Binary files /dev/null and b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/table/filter/funnel_delete.png differ

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/CollectionUtils.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/CollectionUtils.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/CollectionUtils.java
new file mode 100644
index 0000000..6a58d72
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/CollectionUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util;
+
+import java.util.Collection;
+import java.util.TreeSet;
+
+public class CollectionUtils {
+
+	/**
+	 * Checks if collection is empty. Null references are considered to be empty collections.
+	 * @param c
+	 * @return true if collection is empty
+	 */
+	public static final boolean isEmpty( Collection<?> c ) {
+		return c == null || c.isEmpty();
+	}
+	
+	/**
+	 * Tries to sort collection. All elements have to implement Comparable interface and
+	 * be mutually comparable 
+	 * @param <T>
+	 * @param any collection
+	 * @return new sorted collection if succeeded otherwise same collection
+	 */
+	public static <T> Collection<T> trySort(  Collection<T> c ) {
+		try {
+			return new TreeSet<T>( c );
+		} catch( Throwable ex ) {
+		}
+		return c;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopy.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopy.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopy.java
new file mode 100644
index 0000000..62065cf
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopy.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util;
+
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.oxbow.swingbits.util.copy.FastByteArrayInputStream;
+import org.oxbow.swingbits.util.copy.FastByteArrayOutputStream;
+
+/**
+ * Utility for object deep copying (vs. clone()'s shallow copying)
+ */
+public class DeepCopy {
+
+	/**
+	 * Creates deep copy of the object.
+	 * @param originalObject object to copy
+	 * @return copy of originalObject
+	 * @throws DeepCopyException if operation cannot be performed
+	 */
+	public static final <T extends Serializable> T copy( T originalObject ) {
+    	return DeepCopy.<T>restore( (FastByteArrayInputStream) store( originalObject ).getInputStream() );
+    }
+
+    public static final <T extends Serializable> FastByteArrayOutputStream store( T obj ) {
+
+    	try {
+
+	    	FastByteArrayOutputStream fbos = new FastByteArrayOutputStream();
+	        ObjectOutputStream out = new ObjectOutputStream(fbos);
+	        out.writeObject( obj );
+	        out.flush();
+	        out.close();
+
+	        return fbos;
+
+	    } catch( Throwable ex ) {
+
+	  	    throw new DeepCopyException("An " + obj.getClass().getSimpleName() + " cannot be serialized. The reason: " + ex.getLocalizedMessage(), ex);
+	    }
+
+    }
+
+    @SuppressWarnings("unchecked")
+	public static final <T extends Serializable> T restore( FastByteArrayInputStream  stream) {
+
+    	try {
+
+	    	ObjectInputStream in = new ObjectInputStream(stream);
+	        return (T) in.readObject();
+
+	    } catch( Throwable ex ) {
+
+	  	    throw new DeepCopyException("An object cannot be deserizalized. The reason: " + ex.getLocalizedMessage(), ex);
+
+	    }
+
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopyException.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopyException.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopyException.java
new file mode 100644
index 0000000..02501bc
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DeepCopyException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util;
+
+public class DeepCopyException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	public DeepCopyException() {
+		super();
+	}
+
+	public DeepCopyException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	public DeepCopyException(String message) {
+		super(message);
+	}
+
+	public DeepCopyException(Throwable cause) {
+		super(cause);
+	}
+
+	
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DefaultObjectToStringTranslator.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DefaultObjectToStringTranslator.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DefaultObjectToStringTranslator.java
new file mode 100644
index 0000000..e3b0e49
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/DefaultObjectToStringTranslator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util;
+
+public class DefaultObjectToStringTranslator implements	IObjectToStringTranslator {
+
+	@Override
+	public String translate(Object obj) {
+		return obj == null? "": obj.toString().toLowerCase();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IObjectToStringTranslator.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IObjectToStringTranslator.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IObjectToStringTranslator.java
new file mode 100644
index 0000000..8edbb91
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IObjectToStringTranslator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util;
+
+public interface IObjectToStringTranslator {
+
+	String translate( Object obj );
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IValueWrapper.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IValueWrapper.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IValueWrapper.java
new file mode 100644
index 0000000..54b43b2
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/IValueWrapper.java
@@ -0,0 +1,7 @@
+package org.oxbow.swingbits.util;
+
+public interface IValueWrapper<T> {
+
+	T getValue();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Markup.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Markup.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Markup.java
new file mode 100644
index 0000000..f6fc704
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Markup.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util;
+
+import java.awt.Color;
+import java.awt.Font;
+
+public final class Markup {
+
+	private static final String HTML_START = "<html>";
+	private static final String HTML_END   = "</html>";
+	private static final String HTML_BREAK = "<br>";
+
+	private Markup() {}
+
+	public static final String toHex( Color color ) {
+		color = color == null ? Color.BLACK: color;
+		String rgb = Integer.toHexString(color.getRGB());
+		return rgb.substring(2, rgb.length());
+	}
+
+	/**
+	 * Converts string to simple &lt;HTML&gt; presentation.<br>
+	 * Replaces EOLs with &lt;BR&gt; tags
+	 * @param s
+	 * @param finalize if true wraps text with &lt;HTML&gt; tags
+	 * @return
+	 */
+	public final static String toHTML( String s, boolean finalize ) {
+
+		s = s == null? "": s.replaceAll("\n", HTML_BREAK);
+		String tmp = s.trim().toLowerCase();
+
+		StringBuilder sb = new StringBuilder(s);
+
+		if ( finalize ) {
+			if ( !tmp.startsWith(HTML_START)) sb.insert(0, HTML_START);
+			if ( !tmp.endsWith(HTML_END))     sb.append( HTML_END );
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * Converts string to simple &lt;HTML&gt; presentation.<br>
+	 * Replaces EOLs with &lt;BR&gt; tags, wraps text with &lt;HTML&gt; tags
+	 * @param s
+	 * @return
+	 */
+	public final static String toHTML( String s ) {
+		return toHTML( s, true );
+	}
+
+	/**
+	 * Converts font to CSS style
+	 * @param font
+	 * @return CSS style as string
+	 */
+	public final static String toCSS( Font font ) {
+
+		return String.format( "font-family: \"%s\"; %s; %s;",
+				  font.getFamily(),
+				  toSizeCSS(font),
+				  toStyleCSS(font) );
+
+	}
+
+	public final static String toSizeCSS( Font font ) {
+		//TODO: use Toolkit.getDefaultToolkit().getScreenResolution() to calculate font size in pixels
+
+		return String.format( "font-size: %fpx", font.getSize() * .75); // converts to pixels with standard DPI
+	}
+
+	public final static String toStyleCSS( Font font ) {
+
+		switch ( font.getStyle() ) {
+			case Font.ITALIC: return "font-style : italic";
+			case Font.BOLD  : return "font-weight: bold";
+			default         : return "font-weight: normal";
+
+		}
+
+	}
+
+	/**
+	 * Converts color to CSS style
+	 * @param color
+	 * @return CSS style as string
+	 */
+	public final static String toCSS( Color color ) {
+		return  String.format( "color: #%s;", toHex(color));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/OperatingSystem.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/OperatingSystem.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/OperatingSystem.java
new file mode 100644
index 0000000..2171ade
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/OperatingSystem.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util;
+
+/**
+ * Utility class to allow OS determination
+ *
+ * Created on Mar 11, 2010
+ * @author Eugene Ryzhikov
+ *
+ */
+public enum OperatingSystem {
+
+	WINDOWS( "windows" ),
+	MACOS( "mac" ),
+	LINUX( "linux" ),
+	UNIX( "nix" ),
+	SOLARIS( "solaris" ),
+	
+	UNKNOWN( "unknown" ) {
+		@Override protected boolean isReal() { return false; }
+	};
+
+
+	private String tag;
+
+	OperatingSystem( String tag ) {
+		this.tag = tag;
+	}
+
+	public boolean isCurrent() {
+		return isReal() && getName().toLowerCase().indexOf(tag) >=0;
+	}
+
+	public static final String getName() {
+		return System.getProperty("os.name");
+	}
+
+	public static final String getVersion() {
+		return System.getProperty("os.version");
+	}
+
+	public static final String getArchitecture() {
+		return System.getProperty("os.arch");
+	}
+
+	@Override
+	public final String toString() {
+		return String.format("%s v%s (%s)", getName(), getVersion(), getArchitecture() );
+	}
+	
+	protected boolean isReal() {
+		return true;
+	}
+
+	/**
+	 * Returns current operating system
+	 * @return current operating system or UNKNOWN if not found
+	 */
+	public static final OperatingSystem getCurrent() {
+
+		for( OperatingSystem os: OperatingSystem.values() ) {
+			if ( os.isCurrent() ) return os;
+		}
+		return UNKNOWN;
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Preconditions.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Preconditions.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Preconditions.java
new file mode 100644
index 0000000..8697467
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Preconditions.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util;
+
+public class Preconditions {
+
+	private Preconditions(){}
+	
+	public static void checkArgument(boolean expression) {
+	    if (!expression) throw new IllegalArgumentException();
+    }
+	
+	public static void checkArgument(boolean expression, String message ) {
+	    if (!expression) throw new IllegalArgumentException( String.valueOf(message));
+    }
+	
+	public static <T> T checkNotNull(T ref) {
+		if (ref == null) throw new NullPointerException();
+		return ref;
+	}
+
+	public static <T> T checkNotNull(T ref, String message ) {
+		if (ref == null) throw new NullPointerException(String.valueOf(message));
+		return ref;
+	}
+	
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Screenshot.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Screenshot.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Screenshot.java
new file mode 100644
index 0000000..698686e
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Screenshot.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util;
+
+import java.awt.AWTException;
+import java.awt.AWTPermission;
+import java.awt.DisplayMode;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+public class Screenshot {
+
+	private final BufferedImage image;
+
+
+	/**
+     * Creates an image containing pixels read from the screen.  This image does
+     * not include the mouse cursor.
+	 * @param screenRect Rect to capture in screen coordinates
+	 * @return captured screenshot
+     * @throws 	IllegalArgumentException if <code>screenRect</code> width and height are not greater than zero
+     * @throws 	SecurityException if <code>readDisplayPixels</code> permission is not granted
+	 * @throws AWTException
+     * @see     SecurityManager#checkPermission
+     * @see 	AWTPermission
+	 */
+	public static final Screenshot capture( Rectangle screenRect ) throws AWTException {
+		return new Screenshot( getRobot().createScreenCapture( screenRect ));
+	}
+
+	public static final Screenshot capture( int width, int height ) throws AWTException {
+		return capture( new Rectangle( width, height ));
+	}
+
+	
+	private static Robot robot;
+
+	private synchronized static Robot getRobot() throws AWTException {
+
+		if ( robot == null ) robot = new Robot();
+		return robot;
+
+	}
+
+	private Screenshot( BufferedImage image ) {
+		this.image = image;
+	}
+
+	/**
+	 * Returns the image screenshot is based on
+	 */
+	public Image getImage() {
+		return image;
+	}
+
+
+	/**
+     * Writes an image using an arbitrary <code>ImageWriter</code>
+     * that supports the given format to a <code>File</code>.  If
+     * there is already a <code>File</code> present, its contents are
+     * discarded.
+	 * @param formatName a <code>String</code> containg the informal name of the format.
+	 * @param output a <code>File</code> to be written to
+	 *
+	 * if an error occurs during writing.
+	 *
+     * @exception IllegalArgumentException if any parameter is <code>null</code>.
+	 * @throws IOException if an error occurs during writing.
+	 */
+	public boolean store( String formatName, File output ) throws IOException {
+		return ImageIO.write( image, formatName, output );
+	}
+	
+	/**
+	 * Retrieves screen information as a list of display modes, 
+	 * which includes screen dimensions, bit depth and refresh rate
+	 * @return
+	 */
+	public static final List<DisplayMode> getDisplayInfo() {
+		
+		List<DisplayMode> result = new ArrayList<DisplayMode>();
+		for (GraphicsDevice gs:  GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
+			result.add( gs.getDisplayMode());
+		}
+		return result;
+		
+	}
+
+
+//	public static void main(String[] args) {
+//
+//		try {
+//			System.out.println("taking screenshot...");
+//			
+//			DisplayMode dm = getDisplayInfo().get(0);
+//			Screenshot.capture( dm.getWidth(), dm.getHeight()).store( "jpg", new File("C:/home/imageTest.jpg") );
+//		} catch (Throwable e) {
+//			e.printStackTrace();
+//		}
+//
+//	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Strings.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Strings.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Strings.java
new file mode 100644
index 0000000..af784b4
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/Strings.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class Strings {
+
+	private Strings(){};
+
+	/**
+	 * Check if string is empty
+	 * @param s
+	 * @return true if string is null or empty (white spaces are not counted)
+	 */
+	public final static boolean isEmpty( String s ) {
+		return s == null || s.trim().length() == 0;
+	}
+
+
+	/**
+	 * Returns safe string - never null
+	 * @param s
+	 * @return
+	 */
+	public final static String safe( String s ) {
+		return isEmpty(s)? "": s;
+	}
+
+	/**
+	 * Capitalize every word in the string
+	 * @param s
+	 * @return
+	 */
+	public final static String capitalize( String s ) {
+
+		if ( isEmpty(s) ) return s;
+
+		StringBuilder sb = new StringBuilder();
+		for( String w: s.split(" ") ) {
+			sb.append( capitalizeWord(w) );
+			sb.append(' ');
+		}
+		return sb.toString().trim();
+	}
+
+	/**
+	 * Capitalizes given word
+	 * @param word
+	 * @return
+	 */
+	private final static String capitalizeWord( String word ) {
+
+		if ( isEmpty(word) ) return word;
+		String capital = word.substring(0, 1).toUpperCase();
+		return ( word.length() == 1 )? capital: capital + word.substring(1).toLowerCase();
+
+	}
+
+
+	/**
+	 * Converts exception stack trace as string
+	 * @param ex
+	 * @return
+	 */
+	public static final String stackStraceAsString( Throwable ex ) {
+		StringWriter sw = new StringWriter();
+	    ex.printStackTrace(new PrintWriter(sw));
+	    return sw.toString();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayInputStream.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayInputStream.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayInputStream.java
new file mode 100644
index 0000000..d1e66a0
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayInputStream.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+package org.oxbow.swingbits.util.copy;
+
+
+import java.io.InputStream;
+
+/**
+ * ByteArrayInputStream implementation that does not synchronize methods.
+ */
+public class FastByteArrayInputStream extends InputStream {
+	
+    /**
+     * Our byte buffer
+     */
+    protected byte[] buf = null;
+
+    /**
+     * Number of bytes that we can read from the buffer
+     */
+    protected int count = 0;
+
+    /**
+     * Number of bytes that have been read from the buffer
+     */
+    protected int pos = 0;
+
+    public FastByteArrayInputStream(byte[] buf, int count) {
+        this.buf = buf;
+        this.count = count;
+    }
+
+    public final int available() {
+        return count - pos;
+    }
+
+    public final int read() {
+        return (pos < count) ? (buf[pos++] & 0xff) : -1;
+    }
+
+    public final int read(byte[] b, int off, int len) {
+        if (pos >= count)
+            return -1;
+
+        if ((pos + len) > count)
+            len = (count - pos);
+
+        System.arraycopy(buf, pos, b, off, len);
+        pos += len;
+        return len;
+    }
+
+    public final long skip(long n) {
+        if ((pos + n) > count)
+            n = count - pos;
+        if (n < 0)
+            return 0;
+        pos += n;
+        return n;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayOutputStream.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayOutputStream.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayOutputStream.java
new file mode 100644
index 0000000..559ca81
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/copy/FastByteArrayOutputStream.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util.copy;
+
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * ByteArrayOutputStream implementation that doesn't synchronize methods
+ * and doesn't copy the data on toByteArray().
+ */
+public class FastByteArrayOutputStream extends OutputStream {
+    /**
+     * Buffer and size
+     */
+    protected byte[] buf = null;
+    protected int size = 0;
+
+    /**
+     * Constructs a stream with buffer capacity size 5K 
+     */
+    public FastByteArrayOutputStream() {
+        this(5 * 1024);
+    }
+
+    /**
+     * Constructs a stream with the given initial size
+     */
+    public FastByteArrayOutputStream(int initSize) {
+        this.size = 0;
+        this.buf = new byte[initSize];
+    }
+
+    /**
+     * Ensures that we have a large enough buffer for the given size.
+     */
+    private void verifyBufferSize(int sz) {
+        if (sz > buf.length) {
+            byte[] old = buf;
+            buf = new byte[Math.max(sz, 2 * buf.length )];
+            System.arraycopy(old, 0, buf, 0, old.length);
+//            old = null;
+        }
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    /**
+     * Returns the byte array containing the written data. Note that this
+     * array will almost always be larger than the amount of data actually
+     * written.
+     */
+    public byte[] getByteArray() {
+        return buf;
+    }
+
+    public final void write(byte b[]) {
+        verifyBufferSize(size + b.length);
+        System.arraycopy(b, 0, buf, size, b.length);
+        size += b.length;
+    }
+
+    public final void write(byte b[], int off, int len) {
+        verifyBufferSize(size + len);
+        System.arraycopy(b, off, buf, size, len);
+        size += len;
+    }
+
+    public final void write(int b) {
+        verifyBufferSize(size + 1);
+        buf[size++] = (byte) b;
+    }
+
+    public void reset() {
+        size = 0;
+    }
+
+    /**
+     * Returns a ByteArrayInputStream for reading back the written data
+     */
+    public InputStream getInputStream() {
+        return new FastByteArrayInputStream(buf, size);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/AncestorAdapter.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/AncestorAdapter.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/AncestorAdapter.java
new file mode 100644
index 0000000..252e986
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/AncestorAdapter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util.swing;
+
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
+
+public class AncestorAdapter implements AncestorListener {
+
+	@Override
+	public void ancestorAdded(AncestorEvent event) {
+	}
+
+	@Override
+	public void ancestorRemoved(AncestorEvent event) {
+	}
+
+	@Override
+	public void ancestorMoved(AncestorEvent event) {
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/BeanProperty.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/BeanProperty.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/BeanProperty.java
new file mode 100644
index 0000000..ff59fca
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/BeanProperty.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util.swing;
+
+import java.beans.PropertyChangeSupport;
+
+/**
+ * Incupsulates Bean Property concept. 
+ * Includes automated property change notifications
+ * @author Eugene Ryzhikov
+ *
+ * @param <T>
+ */
+public abstract class BeanProperty<T> {
+
+	private PropertyChangeSupport notificator;
+	private String propertyName;
+	private boolean forceChange;
+
+	public BeanProperty( PropertyChangeSupport notificator, String propertyName, boolean forceSet ) {
+		this.notificator = notificator;
+		this.propertyName = propertyName;
+		this.forceChange = forceSet;
+	}
+	
+	public BeanProperty( PropertyChangeSupport notificator, String propertyName) {
+		this( notificator, propertyName, false );
+	}
+	
+	/**
+	 * Returns property value
+	 * @return
+	 */
+	public abstract T get();
+	
+	/**
+	 * Sets property value
+	 * @param value
+	 */
+	protected abstract void setValue( T value );
+	
+	/**
+	 * Sets property value. Sends property change notification if value is actually changed
+	 * @param newValue
+	 * @return true if value was changed
+	 */
+	public final boolean set( T newValue ) {
+		
+		boolean result;
+		T oldValue = get();
+		if ( result = forceChange || !sameValues( oldValue, newValue )) {
+			setValue(newValue);
+			notificator.firePropertyChange( propertyName, oldValue, newValue );
+		}
+		return result;
+		
+	}
+	
+	private boolean sameValues( T a, T b ) {
+	   return a == b || ( a != null && b != null && a.equals( b ));
+	}
+	
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/4c3a7698/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/CompoundIcon.java
----------------------------------------------------------------------
diff --git a/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/CompoundIcon.java b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/CompoundIcon.java
new file mode 100644
index 0000000..e355236
--- /dev/null
+++ b/launchers/marmotta-splash/src/main/java/org/oxbow/swingbits/util/swing/CompoundIcon.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2009-2011, EzWare
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.Neither the name of the
+ * EzWare nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package org.oxbow.swingbits.util.swing;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * The CompoundIcon will paint two, or more, Icons as a single Icon. The Icons
+ * are painted in the order in which they are added.
+ * 
+ * The Icons can be laid out
+ * <ul>
+ * <li>Horizontally
+ * <li>Vertically
+ * <li>Stacked
+ * </ul>
+ * 
+ */
+public class CompoundIcon implements Icon {
+	public enum Layout {
+		HORIZONTAL, VERTICAL, STACKED;
+	}
+
+	public final static float TOP = 0.0f;
+	public final static float LEFT = 0.0f;
+	public final static float CENTER = 0.5f;
+	public final static float BOTTOM = 1.0f;
+	public final static float RIGHT = 1.0f;
+
+	private Icon[] icons;
+
+	private Layout layout;
+
+	private int gap;
+
+	private float alignmentX = CENTER;
+	private float alignmentY = CENTER;
+
+	/**
+	 * Convenience constructor for creating a CompoundIcon where the icons are
+	 * laid out horizontally, the gap is 0 and the X/Y alignments will default
+	 * to CENTER.
+	 * 
+	 * @param icons
+	 *            the Icons to be painted as part of the CompoundIcon
+	 */
+	public CompoundIcon(Icon... icons) {
+		this(Layout.HORIZONTAL, icons);
+	}
+
+	/**
+	 * Convenience constructor for creating a CompoundIcon where the gap is 0
+	 * and the X/Y alignments will default to CENTER.
+	 * 
+	 * @param layout
+	 *            the layout used to lay out the icons for painting.
+	 * @param icons
+	 *            the Icons to be painted as part of the CompoundIcon
+	 */
+	public CompoundIcon(Layout layout, Icon... icons) {
+		this(layout, 0, icons);
+	}
+
+	/**
+	 * Convenience constructor for creating a CompoundIcon where the X/Y
+	 * alignments will default to CENTER.
+	 * 
+	 * @param layout
+	 *            the layout used to lay out the icons for painting
+	 * @param gap
+	 *            the gap between the icons
+	 * @param icons
+	 *            the Icons to be painted as part of the CompoundIcon
+	 */
+	public CompoundIcon(Layout layout, int gap, Icon... icons) {
+		this(layout, gap, CENTER, CENTER, icons);
+	}
+
+	/**
+	 * Create a CompoundIcon specifying all the properties.
+	 * 
+	 * @param layout
+	 *            the layout used to lay out the icons for painting
+	 * @param gap
+	 *            the gap between the icons
+	 * @param alignmentX
+	 *            the X alignment of the icons. Common values are LEFT, CENTER,
+	 *            RIGHT. Can be any value between 0.0 and 1.0
+	 * @param alignmentY
+	 *            the Y alignment of the icons. Common values are TOP, CENTER,
+	 *            BOTTOM. Can be any value between 0.0 and 1.0
+	 * @param icons
+	 *            the Icons to be painted as part of the CompoundIcon
+	 */
+	public CompoundIcon(Layout layout, int gap, float alignmentX,
+			float alignmentY, Icon... icons) {
+		this.layout = layout;
+		this.gap = gap;
+		this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f
+				: alignmentX;
+		this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f
+				: alignmentY;
+
+		for (int i = 0; i < icons.length; i++) {
+			if (icons[i] == null) {
+				throw new IllegalArgumentException("Icon (" + i
+						+ ") cannot be null");
+			}
+		}
+
+		this.icons = icons;
+	}
+
+	/**
+	 * Get the layout along which each icon is painted.
+	 * 
+	 * @return the layout
+	 */
+	public Layout getLayout() {
+		return layout;
+	}
+
+	/**
+	 * Get the gap between each icon
+	 * 
+	 * @return the gap in pixels
+	 */
+	public int getGap() {
+		return gap;
+	}
+
+	/**
+	 * Get the alignment of the icon on the x-layout
+	 * 
+	 * @return the alignment
+	 */
+	public float getAlignmentX() {
+		return alignmentX;
+	}
+
+	/**
+	 * Get the alignment of the icon on the y-layout
+	 * 
+	 * @return the alignment
+	 */
+	public float getAlignmentY() {
+		return alignmentY;
+	}
+
+	/**
+	 * Get the number of Icons contained in this CompoundIcon.
+	 * 
+	 * @return the total number of Icons
+	 */
+	public int getIconCount() {
+		return icons.length;
+	}
+
+	/**
+	 * Get the Icon at the specified index.
+	 * 
+	 * @param index
+	 *            the index of the Icon to be returned
+	 * @return the Icon at the specified index
+	 * @exception IndexOutOfBoundsException
+	 *                if the index is out of range
+	 */
+	public Icon getIcon(int index) {
+		return icons[index];
+	}
+
+	// ///// Icon Interface /////////////////////////////
+
+	/**
+	 * Gets the width of this icon.
+	 * 
+	 * @return the width of the icon in pixels.
+	 */
+	@Override
+	public int getIconWidth() {
+		int width = 0;
+
+		// Add the width of all Icons while also including the gap
+		if (layout == Layout.HORIZONTAL) {
+			width += (icons.length - 1) * gap;
+			for (Icon icon : icons)
+				width += icon.getIconWidth();
+		} else { // Just find the maximum width
+			for (Icon icon : icons)
+				width = Math.max(width, icon.getIconWidth());
+		}
+
+		return width;
+	}
+
+	/**
+	 * Gets the height of this icon.
+	 * 
+	 * @return the height of the icon in pixels.
+	 */
+	@Override
+	public int getIconHeight() {
+		int height = 0;
+
+		// Add the height of all Icons while also including the gap
+		if (layout == Layout.VERTICAL) {
+			height += (icons.length - 1) * gap;
+
+			for (Icon icon : icons)
+				height += icon.getIconHeight();
+		} else // Just find the maximum height
+		{
+			for (Icon icon : icons)
+				height = Math.max(height, icon.getIconHeight());
+		}
+
+		return height;
+	}
+
+	/**
+	 * Paint the icons of this compound icon at the specified location
+	 * 
+	 * @param c The component on which the icon is painted 
+	 *            
+	 * @param g the graphics context
+	 *            
+	 * @param x the X coordinate of the icon's top-left corner
+	 *            
+	 * @param y the Y coordinate of the icon's top-left corner
+	 *            
+	 */
+	@Override
+	public void paintIcon(Component c, Graphics g, int x, int y) {
+		if (layout == Layout.HORIZONTAL) {
+			int height = getIconHeight();
+
+			for (Icon icon : icons) {
+				int iconY = getOffset(height, icon.getIconHeight(), alignmentY);
+				icon.paintIcon(c, g, x, y + iconY);
+				x += icon.getIconWidth() + gap;
+			}
+		} else if (layout == Layout.VERTICAL) {
+			int width = getIconWidth();
+
+			for (Icon icon : icons) {
+				int iconX = getOffset(width, icon.getIconWidth(), alignmentX);
+				icon.paintIcon(c, g, x + iconX, y);
+				y += icon.getIconHeight() + gap;
+			}
+		} else  {// must be Z_layout
+		
+			int width = getIconWidth();
+			int height = getIconHeight();
+
+			for (Icon icon : icons) {
+				int iconX = getOffset(width, icon.getIconWidth(), alignmentX);
+				int iconY = getOffset(height, icon.getIconHeight(), alignmentY);
+				icon.paintIcon(c, g, x + iconX, y + iconY);
+			}
+		}
+	}
+
+	/*
+	 * When the icon value is smaller than the maximum value of all icons the
+	 * icon needs to be aligned appropriately. Calculate the offset to be used
+	 * when painting the icon to achieve the proper alignment.
+	 */
+	private int getOffset(int maxValue, int iconValue, float alignment) {
+		float offset = (maxValue - iconValue) * alignment;
+		return Math.round(offset);
+	}
+}