text:
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
using Shared;
using CoreGraphics;
using System.Collections.Generic;
using Shared.DataBase;
using Shared.Enums;
using System.Linq;

namespace Mit4RobotApp
{
	partial class VCHighScoresMenu : UIViewController
	{
		private Dictionary <int, EDifficulty> difficulties;
		private UIActionSheet actionDifficulty;
		private EDifficulty selectedDifficulty;

		public VCHighScoresMenu(IntPtr handle) : base(handle)
		{
		}

		public override void ViewDidLoad()
		{
			base.ViewDidLoad();

			selectedDifficulty = EDifficulty.Easy;

			#region select difficulty
			difficulties = new Dictionary<int, EDifficulty>();

			actionDifficulty = new UIActionSheet();

			actionDifficulty.Title = "Selecteer de moeilijkheidsgraad";

			int index = 0;

			foreach (var item in Enum.GetValues(typeof(EDifficulty)))
			{
				if ((EDifficulty)item != EDifficulty.Custom && (EDifficulty)item != EDifficulty.None)
				{
					difficulties.Add(index, (EDifficulty)item);

					actionDifficulty.Add(item.ToString());

					index++;
				}
			}

			actionDifficulty.Add("Annuleer");

			actionDifficulty.Clicked += (sender1, e1) =>
			{
				if (e1.ButtonIndex != actionDifficulty.ButtonCount - 1)
				{
					selectedDifficulty = difficulties[(int)e1.ButtonIndex];

					UpdateTableView();
				}
			};
			#endregion

			btnDifficulty.TouchUpInside += (object sender, EventArgs e) =>
			{
				actionDifficulty.ShowInView(scrollView);
			};
		}

		public override void ViewWillAppear(bool animated)
		{
			base.ViewWillAppear(animated);

			UpdateGUI();
			UpdateTableView();
		}

		public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
		{
			base.DidRotate(fromInterfaceOrientation);

			UpdateGUI();
			UpdateTableView();
		}

		public void UpdateGUI()
		{
			GlobalSupport.UpdateScreenSize(new CGRect(
					0,
					0,
					UIScreen.MainScreen.Bounds.Width,
					UIScreen.MainScreen.Bounds.Height));

			scrollView.Frame = GlobalSupport.MainCGRect;

			nfloat yCoordinate = 5;

			btnDifficulty.Frame = GlobalSupport.FullWidthCGRect(yCoordinate);

			yCoordinate += btnDifficulty.Frame.Height + 5;

			tbHighscores.Frame = new CGRect(
				5,
				yCoordinate,
				GlobalSupport.ScreenWidth - 10,
				GlobalSupport.ScreenHeight - yCoordinate);
		}

		public void UpdateTableView()
		{
			TBSHighScores source = new TBSHighScores(HighscoreSelectDifficulty(selectedDifficulty.ToString()).ToArray());
			source.OnRowSelected += (object sender, TBSHighScores.RowSelectedEventArgs e) =>
			{
				string lblText = tbHighscores.Source.GetCell(tbHighscores, e.indexPath).TextLabel.Text;
				string[] split = lblText.Split(':');
				if (split[1].Replace(" ", "") == "Nohighscore")
				{
					GlobalSupport.ShowPopupMessage("Sorry, you have to get a highscore to share first!");
				}
				else
				{
					ShareScore(split[0], split[1].Replace(" ", ""));
				}

			};

			tbHighscores.Source = source;
			tbHighscores.ReloadData();
		}

		public void ShareScore(string level, string score)
		{
			string toShare = "I got " + score + " points on " + level + " in the ProgramADroid app. Can you beat me?";

			UIActivityViewController activityShare = new UIActivityViewController(
				                                         new NSObject[]	{ UIActivity.FromObject(toShare) },
				                                         null);
			this.NavigationController.PresentViewController(activityShare, true, null);
		}

		private List<string> HighscoreSelectDifficulty(string difficulty)
		{
			List<string> highscoreStrings = new List<string>();
			DataBase db = DataBase.Instance();
			List<HighScore> highscores = db.SelectAll<HighScore>();

			List<string> levelList = new List<string>();

			int items = 1;
			string toAdd = "";

			switch (selectedDifficulty)
			{
				case EDifficulty.Easy:
					items = 11;
					toAdd = "Easy";
					break;
				case EDifficulty.Medium:
					items = 13;
					toAdd = "Medium";
					break;
				case EDifficulty.Hard:
					items = 12;
					toAdd = "Hard";
					break;
			}

			for (int i = 0; i < items; i++)
			{
				if (i < 9)
				{
					levelList.Add(toAdd + "0" + (i + 1) + ".tmx".ToString());
				}
				else
				{
					levelList.Add(toAdd + (i + 1) + ".tmx".ToString());
				}
			}

			foreach (var item in levelList)
			{
				string levelName = item.Substring (0,item.LastIndexOf("."));

				try
				{

					HighScore highest = highscores.Where(x => x.Level == item).OrderByDescending(x => x.Score).First();
					highscoreStrings.Add(levelName + ": " + highest.Score + " : " + highest.Name + " : " + highest.Date.ToShortDateString());
				}
				catch (Exception)
				{
					// No highscore for this level.
					highscoreStrings.Add(levelName + ": " + "No highscore");
				}
			}

			return highscoreStrings;
		}
	}
}


text:
package csicommon

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	mount "k8s.io/mount-utils"
)

var fakeID = "fake-id"

func TestGetReqID(t *testing.T) {
	t.Parallel()
	req := []interface{}{
		&csi.CreateVolumeRequest{
			Name: fakeID,
		},
		&csi.DeleteVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.CreateSnapshotRequest{
			Name: fakeID,
		},
		&csi.DeleteSnapshotRequest{
			SnapshotId: fakeID,
		},

		&csi.ControllerExpandVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.NodeStageVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.NodeUnstageVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.NodePublishVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.NodeUnpublishVolumeRequest{
			VolumeId: fakeID,
		},
		&csi.NodeExpandVolumeRequest{
			VolumeId: fakeID,
		},
	}
	for _, r := range req {
		if got := getReqID(r); got != fakeID {
			t.Errorf("getReqID() = %v, want %v", got, fakeID)
		}
	}

	// test for nil request
	if got := getReqID(nil); got != "" {
		t.Errorf("getReqID() = %v, want empty string", got)
	}
}

func TestFilesystemNodeGetVolumeStats(t *testing.T) {
	t.Parallel()

	// ideally this is tested on different filesystems, including CephFS,
	// but we'll settle for the filesystem where the project is checked out
	cwd, err := os.Getwd()
	require.NoError(t, err)

	// retry until a mountpoint is found
	for {
		stats, err := FilesystemNodeGetVolumeStats(context.TODO(), mount.New(""), cwd, true)
		if err != nil && cwd != "/" && strings.HasSuffix(err.Error(), "is not mounted") {
			// try again with the parent directory
			cwd = filepath.Dir(cwd)

			continue
		}

		require.NoError(t, err)
		assert.NotEqual(t, len(stats.Usage), 0)
		for _, usage := range stats.Usage {
			assert.NotEqual(t, usage.Available, -1)
			assert.NotEqual(t, usage.Total, -1)
			assert.NotEqual(t, usage.Used, -1)
			assert.NotEqual(t, usage.Unit, 0)
		}

		// tests done, no need to retry again
		break
	}
}

func TestRequirePositive(t *testing.T) {
	t.Parallel()

	assert.Equal(t, requirePositive(0), int64(0))
	assert.Equal(t, requirePositive(-1), int64(0))
	assert.Equal(t, requirePositive(1), int64(1))
}

func TestIsBlockMultiNode(t *testing.T) {
	t.Parallel()

	blockCap := &csi.VolumeCapability{
		AccessType: &csi.VolumeCapability_Block{
			Block: &csi.VolumeCapability_BlockVolume{},
		},
	}

	fsCap := &csi.VolumeCapability{
		AccessType: &csi.VolumeCapability_Mount{
			Mount: &csi.VolumeCapability_MountVolume{},
		},
	}

	multiNodeCap := &csi.VolumeCapability{
		AccessMode: &csi.VolumeCapability_AccessMode{
			Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
		},
	}

	singleNodeCap := &csi.VolumeCapability{
		AccessMode: &csi.VolumeCapability_AccessMode{
			Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
		},
	}

	tests := []struct {
		name        string
		caps        []*csi.VolumeCapability
		isBlock     bool
		isMultiNode bool
	}{{
		name:        "block/multi-node",
		caps:        []*csi.VolumeCapability{blockCap, multiNodeCap},
		isBlock:     true,
		isMultiNode: true,
	}, {
		name:        "block/single-node",
		caps:        []*csi.VolumeCapability{blockCap, singleNodeCap},
		isBlock:     true,
		isMultiNode: false,
	}, {
		name:        "filesystem/multi-node",
		caps:        []*csi.VolumeCapability{fsCap, multiNodeCap},
		isBlock:     false,
		isMultiNode: true,
	}, {
		name:        "filesystem/single-node",
		caps:        []*csi.VolumeCapability{fsCap, singleNodeCap},
		isBlock:     false,
		isMultiNode: false,
	}}

	for _, test := range tests {
		isBlock, isMultiNode := IsBlockMultiNode(test.caps)
		assert.Equal(t, isBlock, test.isBlock, test.name)
		assert.Equal(t, isMultiNode, test.isMultiNode, test.name)
	}
}

func TestIsFileRWO(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name    string
		caps    []*csi.VolumeCapability
		rwoFile bool
	}{
		{
			name: "non valid",
			caps: []*csi.VolumeCapability{
				{
					AccessMode: nil,
					AccessType: nil,
				},
			},
			rwoFile: false,
		},

		{
			name: "single writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
					},
				},
			},
			rwoFile: true,
		},
		{
			name: "single node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
					},
				},
			},
			rwoFile: true,
		},
		{
			name: "multi node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
					},
				},
			},
			rwoFile: false,
		},
		{
			name: "multi node multi reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
					},
				},
			},
			rwoFile: false,
		},
		{
			name: "single node reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
					},
				},
			},
			rwoFile: false,
		},
	}

	for _, tt := range tests {
		newtt := tt
		t.Run(newtt.name, func(t *testing.T) {
			t.Parallel()
			rwoFile := IsFileRWO(newtt.caps)
			if rwoFile != newtt.rwoFile {
				t.Errorf("IsFileRWO() rwofile = %v, want %v", rwoFile, newtt.rwoFile)
			}
		})
	}
}

func TestIsBlockMultiWriter(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name        string
		caps        []*csi.VolumeCapability
		multiWriter bool
		block       bool
	}{
		{
			name: "non valid",
			caps: []*csi.VolumeCapability{
				{
					AccessMode: nil,
					AccessType: nil,
				},
			},
			multiWriter: false,
			block:       false,
		},
		{
			name: "multi node multi writer block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
					},
				},
			},
			multiWriter: true,
			block:       true,
		},
		{
			name: "single node multi writer block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
					},
				},
			},
			multiWriter: true,
			block:       true,
		},
		{
			name: "single writer block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
					},
				},
			},
			multiWriter: false,
			block:       true,
		},
		{
			name: "single writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
					},
				},
			},
			multiWriter: false,
			block:       false,
		},
		{
			name: "single node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
					},
				},
			},
			multiWriter: true,
			block:       false,
		},
		{
			name: "multi node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
					},
				},
			},
			multiWriter: true,
			block:       false,
		},
		{
			name: "multi node multi reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
					},
				},
			},
			multiWriter: false,
			block:       false,
		},
		{
			name: "single node reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
					},
				},
			},
			multiWriter: false,
			block:       false,
		},
		{
			name: "multi node reader block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
					},
				},
			},
			multiWriter: false,
			block:       true,
		},
		{
			name: "single node reader block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
					},
				},
			},
			multiWriter: false,
			block:       true,
		},
	}

	for _, tt := range tests {
		newtt := tt
		t.Run(newtt.name, func(t *testing.T) {
			t.Parallel()
			multiWriter, block := IsBlockMultiWriter(newtt.caps)
			if multiWriter != newtt.multiWriter {
				t.Errorf("IsBlockMultiWriter() multiWriter = %v, want %v", multiWriter, newtt.multiWriter)
			}
			if block != newtt.block {
				t.Errorf("IsBlockMultiWriter block = %v, want %v", block, newtt.block)
			}
		})
	}
}

func TestIsReaderOnly(t *testing.T) {
	t.Parallel()
	tests := []struct {
		name   string
		caps   []*csi.VolumeCapability
		roOnly bool
	}{
		{
			name: "non valid",
			caps: []*csi.VolumeCapability{
				{
					AccessMode: nil,
					AccessType: nil,
				},
			},
			roOnly: false,
		},

		{
			name: "single writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_SINGLE_WRITER,
					},
				},
			},
			roOnly: false,
		},
		{
			name: "single node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_MULTI_WRITER,
					},
				},
			},
			roOnly: false,
		},
		{
			name: "multi node multi writer FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
					},
				},
			},
			roOnly: false,
		},
		{
			name: "multi node multi reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
					},
				},
			},
			roOnly: true,
		},
		{
			name: "single node reader FS mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Mount{
						Mount: &csi.VolumeCapability_MountVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
					},
				},
			},
			roOnly: true,
		},
		{
			name: "multi node reader block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY,
					},
				},
			},
			roOnly: true,
		},
		{
			name: "single node reader block mode",
			caps: []*csi.VolumeCapability{
				{
					AccessType: &csi.VolumeCapability_Block{
						Block: &csi.VolumeCapability_BlockVolume{},
					},
					AccessMode: &csi.VolumeCapability_AccessMode{
						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY,
					},
				},
			},
			roOnly: true,
		},
	}

	for _, tt := range tests {
		newtt := tt
		t.Run(newtt.name, func(t *testing.T) {
			t.Parallel()
			roOnly := IsReaderOnly(newtt.caps)
			if roOnly != newtt.roOnly {
				t.Errorf("isReadOnly() roOnly = %v, want %v", roOnly, newtt.roOnly)
			}
		})
	}
}

redpajama_set_name: RedPajamaGithub


text:
package net.sf.mmm.client.ui.impl.gwt.widget.complex.adapter;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.mmm.client.ui.api.UiContext;
import net.sf.mmm.client.ui.api.aria.role.Role;
import net.sf.mmm.client.ui.api.attribute.AttributeWriteFlagAdvanced;
import net.sf.mmm.client.ui.api.common.AbstractSize;
import net.sf.mmm.client.ui.api.common.Length;
import net.sf.mmm.client.ui.api.common.LengthProperty;
import net.sf.mmm.client.ui.api.common.SelectionMode;
import net.sf.mmm.client.ui.api.common.Size;
import net.sf.mmm.client.ui.api.common.UiMode;
import net.sf.mmm.client.ui.api.feature.UiFeatureEvent;
import net.sf.mmm.client.ui.api.handler.event.UiHandlerEvent;
import net.sf.mmm.client.ui.api.widget.UiWidgetComposite;
import net.sf.mmm.client.ui.api.widget.UiWidgetRegular;
import net.sf.mmm.client.ui.api.widget.complex.UiWidgetAbstractTree;
import net.sf.mmm.client.ui.api.widget.complex.UiWidgetAbstractTree.UiTreeModel;
import net.sf.mmm.client.ui.api.widget.complex.UiWidgetAbstractTree.UiTreeNodeRenderer;
import net.sf.mmm.client.ui.api.widget.complex.UiWidgetAbstractTree.UiWidgetTreeNode;
import net.sf.mmm.client.ui.base.widget.AbstractUiWidgetNative;
import net.sf.mmm.client.ui.base.widget.complex.AbstractUiWidgetTree;
import net.sf.mmm.client.ui.base.widget.complex.adapter.UiWidgetAdapterTree;
import net.sf.mmm.client.ui.gwt.widgets.HtmlConstants;
import net.sf.mmm.client.ui.impl.gwt.handler.event.EventAdapterGwt;
import net.sf.mmm.client.ui.impl.gwt.widget.adapter.UiWidgetAdapterGwtWidgetActive;
import net.sf.mmm.util.exception.api.IllegalCaseException;
import net.sf.mmm.util.lang.api.function.Consumer;
import net.sf.mmm.util.validation.api.ValidationState;

import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimpleCheckBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;

/**
 * This is the implementation of {@link UiWidgetAdapterTree} using GWT based on {@link Tree}.
 *
 * @param <NODE> is the generic type of the tree-nodes.
 *
 * @author Joerg Hohwiller (hohwille at users.sourceforge.net)
 * @since 1.0.0
 */
public class UiWidgetAdapterGwtTree<NODE> extends UiWidgetAdapterGwtWidgetActive<FlowPanel> implements
    UiWidgetAdapterTree<NODE> {

  /** @see #setRootNode(Object) */
  private NODE rootNode;

  /** @see #setTreeModel(UiTreeModel) */
  private UiTreeModel<NODE> treeModel;

  /** @see #setTreeNodeRenderer(UiTreeNodeRenderer) */
  private UiTreeNodeRenderer<NODE, ?> treeNodeRenderer;

  /** Maps from {@literal <NODE>} to {@link TreeNodeAdapter}. */
  private Map<NODE, TreeNodeAdapter> nodeMap;

  /** @see #setTitle(String) */
  private InlineLabel titleHeader;

  /** @see #getGwtTree() */
  private Tree tree;

  /** @see #getScrollPanel() */
  private ScrollPanel scrollPanel;

  /** @see #setSelectionMode(SelectionMode) */
  private SelectionMode selectionMode;

  /** The {@link TreeNodeAdapter} for {@link #rootNode}. */
  private TreeNodeAdapter rootNodeAdapter;

  /**
   * The constructor.
   */
  public UiWidgetAdapterGwtTree() {

    super();
    this.nodeMap = new HashMap<NODE, TreeNodeAdapter>();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setTreeModel(UiTreeModel<NODE> treeModel) {

    this.treeModel = treeModel;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setTreeNodeRenderer(UiTreeNodeRenderer<NODE, ?> renderer) {

    this.treeNodeRenderer = renderer;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setSelectionMode(SelectionMode selectionMode) {

    if (this.selectionMode == selectionMode) {
      return;
    }
    this.selectionMode = selectionMode;
    if (this.rootNodeAdapter != null) {
      this.rootNodeAdapter.updateSelectionMode();
    }
  }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public boolean setSelectedValue(NODE selectedValue) {
  //
  // TreeNodeAdapter treeNodeAdapter = this.nodeMap.get(selectedValue);
  // if (treeNodeAdapter != null) {
  // if (this.selectionMode == SelectionMode.SINGLE_SELECTION) {
  // getGwtTree().setSelectedItem(treeNodeAdapter);
  // } else {
  // clearMultiSelection();
  // treeNodeAdapter.multiSelectionCheckbox.setValue(Boolean.TRUE);
  // }
  // }
  // }

  /**
   * Clear {@link SimpleCheckBox}es of {@link SelectionMode#MULTIPLE_SELECTION}.
   */
  protected void clearMultiSelection() {

    for (TreeNodeAdapter adapter : this.nodeMap.values()) {
      adapter.multiSelectionCheckbox.setValue(Boolean.FALSE);
    }
  }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public boolean setSelectedValues(List<NODE> selectedValues) {
  //
  // if (this.selectionMode == SelectionMode.MULTIPLE_SELECTION) {
  // clearMultiSelection();
  // for (NODE node : selectedValues) {
  // TreeNodeAdapter treeNodeAdapter = this.nodeMap.get(node);
  // if (treeNodeAdapter != null) {
  // treeNodeAdapter.multiSelectionCheckbox.setValue(Boolean.TRUE);
  // }
  // }
  // }
  // }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public boolean hasSelectedValue() {
  //
  // return (getSelectedValue() != null);
  // }
  //
  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public NODE getSelectedValue() {
  //
  // if (this.selectionMode == SelectionMode.SINGLE_SELECTION) {
  // TreeNodeAdapter selectedItem = (TreeNodeAdapter) getGwtTree().getSelectedItem();
  // if (selectedItem != null) {
  // return selectedItem.node;
  // }
  // } else if (this.selectionMode == SelectionMode.MULTIPLE_SELECTION) {
  // for (TreeNodeAdapter adapter : this.nodeMap.values()) {
  // if (adapter.multiSelectionCheckbox.getValue().booleanValue()) {
  // return adapter.node;
  // }
  // }
  // }
  // return null;
  // }
  //
  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public List<NODE> getSelectedValues() {
  //
  // List<NODE> selectedValues = new LinkedList<NODE>();
  // if (this.selectionMode == SelectionMode.SINGLE_SELECTION) {
  // TreeNodeAdapter selectedItem = (TreeNodeAdapter) getGwtTree().getSelectedItem();
  // if (selectedItem != null) {
  // selectedValues.add(selectedItem.node);
  // }
  // } else if (this.selectionMode == SelectionMode.MULTIPLE_SELECTION) {
  // for (TreeNodeAdapter adapter : this.nodeMap.values()) {
  // if (adapter.multiSelectionCheckbox.getValue().booleanValue()) {
  // selectedValues.add(adapter.node);
  // }
  // }
  // }
  // return selectedValues;
  // }

  // /**
  // * {@inheritDoc}
  // */
  // @Override
  // public int getSelectionCount() {
  //
  // // TODO hohwille implement more efficient!
  // return getSelectedValues().size();
  // }

  /**
   * {@inheritDoc}
   */
  @Override
  public UiWidgetTreeNode<NODE> getTreeNodeWidget(NODE node) {

    TreeNodeAdapter treeNodeAdapter = this.nodeMap.get(node);
    return treeNodeAdapter;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void collapseAllNodes() {

    for (TreeNodeAdapter adapter : this.nodeMap.values()) {
      adapter.setState(false);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void expandNodes() {

    for (TreeNodeAdapter adapter : this.nodeMap.values()) {
      adapter.setState(true);
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setRootNode(NODE node) {

    if (this.rootNode != null) {
      TreeNodeAdapter treeNodeAdapter = this.nodeMap.get(this.rootNode);
      if (treeNodeAdapter != null) {
        treeNodeAdapter.remove();
      }
      this.nodeMap.clear();
    }
    this.rootNode = node;
    this.rootNodeAdapter = createTreeNodeAdapter(this.rootNode);
    this.nodeMap.put(this.rootNode, this.rootNodeAdapter);
    this.rootNodeAdapter.loadChildren();
    getGwtTree().addItem(this.rootNodeAdapter);
  }

  /**
   * @param node is the {@literal <NODE>} to wrap.
   * @return the {@link TreeNodeAdapter} for the given node.
   */
  private TreeNodeAdapter createTreeNodeAdapter(NODE node) {

    UiWidgetRegular widget = this.treeNodeRenderer.create(getUiWidget().getContext());
    TreeNodeAdapter treeNodeAdapter = new TreeNodeAdapter(node, widget);
    return treeNodeAdapter;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected EventAdapterGwt createEventAdapter(UiFeatureEvent source, UiHandlerEvent sender) {

    EventAdapterGwtTree adapter = new EventAdapterGwtTree(source, sender);
    return adapter;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void applyEventAdapterForSelection(EventAdapterGwt adapter) {

    @SuppressWarnings("unchecked")
    HandlerRegistration registration = getGwtTree().addSelectionHandler((EventAdapterGwtTree) adapter);
    addHandlerRegistration(registration);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected Focusable getWidgetAsFocusable() {

    return getGwtTree();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected HasKeyPressHandlers getWidgetAsKeyPressHandlers() {

    return getGwtTree();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected HasAllFocusHandlers getWidgetAsHasAllFocusHandlers() {

    return getGwtTree();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setTitle(String title) {

    getTitleHeader().setText(title);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setEnabled(boolean enabled) {

    if (enabled) {
      getGwtTree().removeStyleName("Disabled");
    } else {
      getGwtTree().addStyleName("Disabled");
    }
  }

  /**
   * @param event is the {@link OpenEvent}.
   */
  private void onOpenEvent(OpenEvent<TreeItem> event) {

    @SuppressWarnings("unchecked")
    TreeNodeAdapter treeNodeAdapter = (TreeNodeAdapter) event.getTarget();
    treeNodeAdapter.loadChildren();
  }

  /**
   * @return the raw GWT {@link Tree}.
   */
  public Tree getGwtTree() {

    if (this.tree == null) {
      this.tree = new Tree();
      this.tree.setTabIndex(HtmlConstants.TAB_INDEX_DISABLE);
      OpenHandler<TreeItem> openHandler = new OpenHandler<TreeItem>() {

        @Override
        public void onOpen(OpenEvent<TreeItem> event) {

          onOpenEvent(event);
        }
      };
      this.tree.addOpenHandler(openHandler);
    }
    return this.tree;
  }

  /**
   * @return the {@link ScrollPanel} containing the {@link #getGwtTree() tree}.
   */
  public ScrollPanel getScrollPanel() {

    if (this.scrollPanel == null) {
      this.scrollPanel = new ScrollPanel(getGwtTree());
    }
    return this.scrollPanel;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected Element getSizeElement() {

    return getScrollPanel().getElement();
  }

  /**
   * @return the titleHeader
   */
  public InlineLabel getTitleHeader() {

    if (this.titleHeader == null) {
      this.titleHeader = new InlineLabel();
      this.titleHeader.setStylePrimaryName("Header");
    }
    return this.titleHeader;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isTitleVisible() {

    return getTitleHeader().isVisible();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setTitleVisible(boolean titleVisible) {

    getTitleHeader().setVisible(titleVisible);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setSummary(String summary) {

    // TODO Auto-generated method stub

  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String getSummary() {

    // TODO Auto-generated method stub
    return null;
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override
  protected AbstractUiWidgetTree<?, NODE> getUiWidgetTyped() {

    return (AbstractUiWidgetTree<?, NODE>) getUiWidget();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected FlowPanel createToplevelWidget() {

    FlowPanel toplevelWidget = new FlowPanel();
    toplevelWidget.add(getTitleHeader());
    toplevelWidget.add(getScrollPanel());
    toplevelWidget.setStylePrimaryName(UiWidgetAbstractTree.STYLE_TREE);
    return toplevelWidget;
  }

  /**
   * This inner class adapts from {@literal <NODE>} to {@link TreeItem}.
   */
  // ATTENTION: This is actually a little dangerous if GWT TreeItem changes on GWT update as it might clash
  // with our own methods. But adding a full-fledged widget and move this into another adapter abstraction per
  // node would be too much overhead and cause bad performance...
  protected class TreeNodeAdapter extends TreeItem implements Consumer<List<NODE>>, ValueChangeHandler<Boolean>,
      ClickHandler, UiWidgetTreeNode<NODE> {

    /** @see #getNode() */
    private final NODE node;

    /** @see #getWidget() */
    private final UiWidgetRegular nodeWidget;

    /** @see #loadChildren() */
    private boolean loaded;

    /** @see #getWidgetPanel() */
    private FlowPanel widgetPanel;

    /** The {@link SimpleCheckBox} for {@link SelectionMode#MULTIPLE_SELECTION}. */
    private SimpleCheckBox multiSelectionCheckbox;

    /** @see #getSize() */
    private Size size;

    /**
     * The dummy constructor.
     */
    private TreeNodeAdapter() {

      super();
      this.loaded = true;
      this.node = null;
      this.nodeWidget = null;
      this.widgetPanel = null;
    }

    /**
     * The constructor.
     *
     * @param node is the unwrapped node (business object).
     * @param widget is the {@link UiWidgetRegular} rendering this node.
     */
    public TreeNodeAdapter(NODE node, UiWidgetRegular widget) {

      super();
      this.nodeWidget = widget;
      this.node = node;
      switch (UiWidgetAdapterGwtTree.this.selectionMode) {
        case SINGLE_SELECTION:
          setWidget(getToplevelWidget(widget));
          break;
        case MULTIPLE_SELECTION:
          initializeMultiSelection();
          break;
        default :
          throw new IllegalCaseException(SelectionMode.class, UiWidgetAdapterGwtTree.this.selectionMode);
      }
      updateNode();
      this.loaded = false;
      // add a dummy child so the node can be expanded for lazy loading...
      addItem(new TreeNodeAdapter());
    }

    /**
     * @return the node
     */
    public NODE getNode() {

      return this.node;
    }

    /**
     * @return the widgetPanel
     */
    public FlowPanel getWidgetPanel() {

      return this.widgetPanel;
    }

    /**
     * Updates the UI of this node.
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected void updateNode() {

      ((UiTreeNodeRenderer) UiWidgetAdapterGwtTree.this.treeNodeRenderer)
          .assignNodeToWidget(this.node, this.nodeWidget);
    }

    /**
     * Loads the children of this node asynchronously.
     */
    protected void loadChildren() {

      if (this.loaded) {
        return;
      }
      UiWidgetAdapterGwtTree.this.treeModel.getChildrenAsync(this.node, this);
      this.loaded = true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void accept(List<NODE> value) {

      clearChildren();
      for (NODE childNode : value) {
        TreeNodeAdapter childNodeAdapter = createTreeNodeAdapter(childNode);
        UiWidgetAdapterGwtTree.this.nodeMap.put(childNode, childNodeAdapter);
        addItem(childNodeAdapter);
      }
    }

    /**
     * Clears all existing children.
     */
    private void clearChildren() {

      if (this.loaded) {
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
          @SuppressWarnings("unchecked")
          TreeNodeAdapter child = (TreeNodeAdapter) getChild(i);
          TreeNodeAdapter oldNode = UiWidgetAdapterGwtTree.this.nodeMap.remove(child.node);
          assert (oldNode == child);
        }
      }
      removeItems();
    }

    /**
     * Recursively updates the {@link SelectionMode}.
     */
    private void updateSelectionMode() {

      switch (UiWidgetAdapterGwtTree.this.selectionMode) {
        case SINGLE_SELECTION:
          if (this.widgetPanel != null) {
            this.multiSelectionCheckbox.setVisible(false);
            // TODO: deselect
          }
          break;
        case MULTIPLE_SELECTION:
          if (this.widgetPanel != null) {
            initializeMultiSelection();
          }
          break;
        default :
          throw new IllegalCaseException(SelectionMode.class, UiWidgetAdapterGwtTree.this.selectionMode);
      }

    }

    /**
     * Initializes checkboxes for {@link SelectionMode#MULTIPLE_SELECTION multi-selection}.
     */
    private void initializeMultiSelection() {

      this.widgetPanel = new FlowPanel();
      this.widgetPanel.setStylePrimaryName("TreeItemContainer");
      this.multiSelectionCheckbox = new SimpleCheckBox();
      this.multiSelectionCheckbox.addClickHandler(this);
      this.widgetPanel.add(this.multiSelectionCheckbox);
      this.widgetPanel.add(getToplevelWidget(this.nodeWidget));
      setWidget(this.widgetPanel);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onClick(ClickEvent event) {

      setNodeSelected(this.multiSelectionCheckbox.getValue().booleanValue());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onValueChange(ValueChangeEvent<Boolean> event) {

      boolean selected = event.getValue().booleanValue();
      setNodeSelected(selected);
    }

    /**
     * Sets the selection state.
     *
     * @param selected - true for selected, false for not selected.
     */
    private void setNodeSelected(boolean selected) {

      String style = "Selected";
      if (selected) {
        this.widgetPanel.addStyleName(style);
      } else {
        this.widgetPanel.removeStyleName(style);
      }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public UiWidgetRegular getNodeWidget() {

      return this.nodeWidget;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isCollapsed() {

      return !getState();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setCollapsed(boolean collapsed) {

      setState(!collapsed);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setTooltip(String tooltip) {

      super.setTitle(tooltip);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getTooltip() {

      return getTitle();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setId(String id) {

      getElement().setId(id);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getId() {

      return getElement().getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public UiMode getMode() {

      return this.nodeWidget.getMode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setMode(UiMode mode) {

      this.nodeWidget.setMode(mode);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setModeFixed(UiMode mode) {

      this.nodeWidget.setModeFixed(mode);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public UiMode getModeFixed() {

      return this.nodeWidget.getModeFixed();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public UiWidgetComposite<?> getParent() {

      return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public NODE getValue() {

      return this.node;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setEnabled(boolean enabled) {

      // TODO hohwille
      this.nodeWidget.setEnabled(enabled);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setVisible(boolean visible, boolean programmatic) {

      setVisible(visible);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isEnabled() {

      return this.nodeWidget.isEnabled();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void dispose() {

      this.nodeWidget.dispose();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isDisposed() {

      return this.nodeWidget.isDisposed();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isVisibleRecursive() {

      if (!getUiWidget().isVisibleRecursive()) {
        return false;
      }
      return isVisible();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public UiContext getContext() {

      return getUiWidget().getContext();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean validate(ValidationState state) {

      return this.nodeWidget.validate(state);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addEventHandler(UiHandlerEvent handler) {

      this.nodeWidget.addEventHandler(handler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean removeEventHandler(UiHandlerEvent handler) {

      return this.nodeWidget.removeEventHandler(handler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setPrimaryStyle(String primaryStyle) {

      setStylePrimaryName(primaryStyle);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setStyles(String styles) {

      super.setStyleName(styles);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getStyles() {

      return getStyleName();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean addStyle(String style) {

      super.addStyleName(style);
      return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean removeStyle(String style) {

      removeStyleName(style);
      return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getPrimaryStyle() {

      return getStylePrimaryName();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean hasStyle(String style) {

      return (AbstractUiWidgetNative.getIndexOfStyle(getStyles(), style) >= 0);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Size getSize() {

      if (this.size == null) {
        this.size = new SizeImpl();
      }
      return this.size;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Role getAriaRole() {

      return this.nodeWidget.getAriaRole();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isModified() {

      return this.nodeWidget.isModified();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public AttributeWriteFlagAdvanced getVisibleFlag() {

      // TODO Auto-generated method stub
      return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void clearMessages() {

      this.nodeWidget.clearMessages();
    }

    /**
     * The implementation of {@link net.sf.mmm.client.ui.api.common.Size} for {@link TreeNodeAdapter}.
     */
    private class SizeImpl extends AbstractSize {

      /**
       * {@inheritDoc}
       */
      @Override
      public void setLength(LengthProperty property, Length length) {

        getElement().getStyle().setProperty(property.getMemberName(), length.toString());
      }

      /**
       * {@inheritDoc}
       */
      @Override
      public Length getLength(LengthProperty property) {

        String value = getSizeElement().getStyle().getProperty(property.getMemberName());
        if (value == null) {
          return property.getDefaultValue();
        }
        return new Length(value);
      }

      /**
       * {@inheritDoc}
       */
      @Override
      public double getWidthInPixel() {

        return getOffsetWidth();
      }

      /**
       * {@inheritDoc}
       */
      @Override
      public double getHeightInPixel() {

        return getOffsetHeight();
      }

    }
  }

  /**
   * @see UiWidgetAdapterGwtTree#createEventAdapter(UiFeatureEvent, UiHandlerEvent)
   */
  private class EventAdapterGwtTree extends EventAdapterGwt implements SelectionHandler<TreeItem> {

    /**
     * The constructor.
     *
     * @param source is the source of the events (typically {@link net.sf.mmm.client.ui.api.widget.UiWidget}).
     * @param sender is the sender of events (an adapter that delegates to the individual handlers/listeners).
     */
    public EventAdapterGwtTree(UiFeatureEvent source, UiHandlerEvent sender) {

      super(source, sender);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onSelection(SelectionEvent<TreeItem> event) {

      @SuppressWarnings("unchecked")
      TreeNodeAdapter selection = (TreeNodeAdapter) event.getSelectedItem();
      Collection<NODE> selectedValues;
      if (selection == null) {
        selectedValues = Collections.emptyList();
      } else {
        selectedValues = Arrays.asList(selection.getNode());
      }
      getUiWidgetTyped().setSelectedValues(selectedValues, false);
    }
  }
}