How to fix customComponent exception

Hello,
i developed a CustomComponent with a verticalLayout as the root panel and a menubar to create a toolbar (using styles).
But the the problem is the removeComponent() method from customcomponent is not overriden it will throw an UnsupportedOperationException(). How would i code this method in my component to support the restart application action in the debug mode for example…

Thank you very much.

One option is to override the removeComponent method in your subclasss of CustomComponent:

public void removeComponent(Component component) {
	// layout is composition root
	layout.removeComponent(component);
}

Thank you for your fast reply.

But what do u refer as the composite root? i considered it as the panel i passed previusly in the setComponentRoot(…) method in the subclass construct, but the problem is still produced.

The example you suggested still produces the exception, so I coded the same i found the removeComponent(Component c) method from AbstractCompononContainer

    /**
     * This only implements the events and component parent calls. The extending
     * classes must implement component list maintenance and call this method
     * before component list maintenance.
     * 
     * @see com.vaadin.ui.ComponentContainer#removeComponent(Component)
     */
    public void removeComponent(Component c) {
        if (c.getParent() == this) {
            c.setParent(null);
            fireComponentDetachEvent(c);
        }
    }

But no when i restart the application, the exception havent been reproduced. But the customcomponent appears twice in the new application.
How can fix that?

Without seeing more code from your class extending CustomComponent, it’s hard to say what the problem is. But copy-pasting removeComponent(Component c) from AbstractCompononContainer is not a correct solution.

-Henri

As Henry said, using the removeComponent method from AbstractComponentContainer does not solve the problem since the method only set the “parent” properties into null without actually removing the component from its parent layout.

When creating a custom component, an approach I usually use is by setting the layout as the component property and create the same “removeComponent” and “addComponent” methods that actually call the equivalent methods of the layout.

Here i paste the full code from the toolbar class using vaadin 6.4.10


/*
 * Copyright 2011 Thingtrack, S.L.
 * 
 * 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 com.thingtrack.vaadin.widgets;

import java.util.ArrayList;
import java.util.List;

import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.VerticalLayout;

/**
 * @author carlos
 * 
 */
public class ToolBar extends CustomComponent {

	public static final String FILE_CATEGORY = "file-category";
	public static final String EDIT_CATEGORY = "edit-category";
	public static final String VIEW_CATEGORY = "view-category";
	public static final String OTHER_CATEGORY = "other-category";

	public static final String CLASSNAME = "v-toolbar";

	private static VerticalLayout mainLayout = new VerticalLayout();
	private static MenuBar menuBar;

	private List<ToolItem> toolItems = new ArrayList<ToolBar.ToolItem>();

	public ToolBar() {

		buildMainLayout();
		setCompositionRoot(mainLayout);
	}

	private VerticalLayout buildMainLayout() {
		// common part: create layout
		mainLayout.setImmediate(false);
		mainLayout.setWidth("100%");
		mainLayout.setHeight("-1px");
		mainLayout.setMargin(false);

		// top-level component properties
		setWidth("100.0%");
		setHeight("100.0%");

		// menuBar
		menuBar = new MenuBar();
		menuBar.setStyleName(CLASSNAME);
		menuBar.setImmediate(false);
		menuBar.setWidth("100.0%");
		menuBar.setHeight("-1px");
		mainLayout.addComponent(menuBar);

		return mainLayout;
	}

	public ToolItem addItem(Resource icon, Command command) {

		return addItem("", icon, command);
	}

	public ToolItem addItem(String caption, Resource icon, Command command) {

		ToolItem toolItem = null;

		MenuItem newItem = menuBar.addItem(caption, icon, null);

		newItem.setStyleName(CLASSNAME + "-item");

		toolItem = new ToolItem(newItem);

		toolItems.add(toolItem);

		return toolItem;

	}

	public boolean removeItem(ToolItem toolItem) {

		if (!toolItems.contains(toolItem)) {

			return false;
		}

		menuBar.removeItem(toolItem.getMenuItem());
		return toolItems.remove(toolItem);

	}

	public ToolItem addSeparator() {

		MenuItem separator = menuBar.addItem("", null);

		separator.setStyleName(CLASSNAME + "-separator");

		ToolItem toolSeparator = new ToolItem(separator);

		toolItems.add(toolSeparator);

		return toolSeparator;
	}

	public boolean removeSeparator(ToolItem toolItem) {

		String separatorClassStyle = CLASSNAME + "-separator";
		String itemStyle = toolItem.getMenuItem().getStyleName();

		if (!separatorClassStyle.equals(itemStyle)) {
			return false;
		}

		if (!toolItems.remove(toolItem)) {
			return false;
		}

		menuBar.removeItem(toolItem.getMenuItem());

		return true;
	}

	public List<ToolItem> getToolItems() {

		return toolItems;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.vaadin.ui.CustomComponent#paintContent(com.vaadin.terminal.PaintTarget
	 * )
	 */
	@Override
	public void paintContent(PaintTarget target) throws PaintException {

		String classItem = CLASSNAME + "-item";
		String classSeparator = CLASSNAME + "-separator";

		if (menuBar != null) {

			for (MenuItem menuitem : menuBar.getItems()) {

				if (menuitem.hasChildren()
						&& classItem.equals(menuitem.getStyleName())) {

					menuitem.setStyleName(CLASSNAME + "-item-bullet");
				}
			}
		}
		super.paintContent(target);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.vaadin.ui.CustomComponent#removeComponent(com.vaadin.ui.Component)
	 */
	@Override
	public void removeComponent(Component c) {

		if (c.getParent() == this) {
			c.setParent(null);

			if (this.getParent() instanceof ComponentContainer) {
				fireEvent(new ComponentDetachEvent(
						(ComponentContainer) this.getParent(), c));
			}
		}
	}

	/**
	 * This interface contains the layer for tool commands of the
	 * {@link com.thingtrack.konekti.widget.CoolBar} class. It's method will
	 * fire when the user clicks on the containing
	 * {@link com.thingtrack.konekti.widget.CoolBar.ToolItem}. The selected item
	 * is given as an argument.
	 */

	public interface Command extends com.vaadin.ui.MenuBar.Command {
	}

	/**
	 * A composite class for tool bar items and menus. You can set commands to
	 * be fired on user click by implementing the
	 * {@link com.vaadin.ui.MenuBar.Command} interface. You can also add
	 * multiple ToolItems to a ToolItem and create a menu.
	 * 
	 */
	public class ToolItem extends CustomComponent {

		private MenuItem menuItem;

		private List<ToolItem> children;

		public ToolItem(MenuItem menuItem) {

			this.menuItem = menuItem;
			this.children = new ArrayList<ToolBar.ToolItem>();
		}

		public void setCommand(Command command) {

			menuItem.setCommand(command);
		}

		public Command getCommand() {

			return (Command) menuItem.getCommand();
		}

		public ToolItem addItem(String caption, Resource icon) {

			MenuItem childMenuItem = this.menuItem.addItem(caption, icon, null);

			ToolItem newToolItem = new ToolItem(childMenuItem);
			children.add(newToolItem);

			return newToolItem;
		}

		public boolean removeItem(ToolItem toolItem) {

			if (!children.contains(toolItem)) {
				return false;
			}

			this.menuItem.removeChild(toolItem.getMenuItem());

			children.remove(toolItem);

			return true;
		}

		public ToolItem addSeparator() {

			MenuItem separator = menuItem.addSeparator();

			ToolItem toolSeparator = new ToolItem(separator);

			children.add(toolSeparator);

			return toolSeparator;

		}

		public boolean removeSeparator(ToolItem toolItem) {

			if (!toolItem.getMenuItem().isSeparator()) {

				return false;
			}

			if (!children.remove(toolItem)) {

				return false;
			}

			menuItem.removeChild(toolItem.getMenuItem());

			return true;
		}

		public boolean hasChildren() {

			return children.size() > 0;
		}

		public List<ToolItem> getToolItems() {

			return children;
		}

		// public void setToolTip(String message) {
		//
		// this.menuItem.setDescription(message);
		// }
		//
		// public String getTooltip() {
		//
		// return this.menuItem.getDescription();
		// }

		protected MenuItem getMenuItem() {
			return menuItem;
		}

	}

}

Finally the solution was to remove the Static to the Menubar and VerticalLayout objects,
menuBar
and
mainLayout
respectaly. I didnt need to override the
removeComponent(Component c)
method from
CustomComponent
in my subclass,
Toolbar
.