PDA

View Full Version : [FNR] gxt 2.0-m1 DragDrop tab support



fulvius
27 Apr 2009, 3:33 PM
Hey guys... I think that I found a bug when put DD support in a tabPanel. To best understand, execute the code below and try do some moves with the tabs... you'll see some inconsistences in console: the tabs in the List<TabsItem> of tabPanel is another sequence in comparation with display in the browser.

Thanks!








package main.client;

import com.extjs.gxt.ui.client.dnd.DragSource;
import com.extjs.gxt.ui.client.dnd.DropTarget;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.DNDEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.VerticalPanel;
import com.extjs.gxt.ui.client.widget.TabItem.HeaderItem;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.button.ToggleButton;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;

public class AdvancedTabExample extends LayoutContainer {

private int index = 0;
private TabPanel advanced;

public AdvancedTabExample() {

setLayout(new FitLayout());

LayoutContainer wrap = new LayoutContainer();
wrap.setLayout(new FitLayout());

VerticalPanel vp = new VerticalPanel();
vp.setSpacing(10);

HorizontalPanel hp = new HorizontalPanel();
hp.setSpacing(5);

Button add = new Button("Add Tab");
add.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
addTab();
advanced.setSelection(advanced.getItem(index - 1));
}
});
hp.add(add);

ToggleButton toggle = new ToggleButton("Enable Tab Context Menu");
toggle.addListener(Events.Toggle, new Listener<ButtonEvent>() {
public void handleEvent(ButtonEvent be) {
advanced.setCloseContextMenu(((ToggleButton) be.getButton())
.isPressed());
}
});
toggle.toggle(true);
hp.add(toggle);
vp.add(hp);

advanced = new TabPanel();
advanced.setMinTabWidth(115);
advanced.setResizeTabs(true);
advanced.setAnimScroll(true);
advanced.setTabScroll(true);
advanced.setCloseContextMenu(true);

while (index < 7) {
addTab();
}

addTabWithPortal();

vp.setStyleAttribute("border", "1px solid red");
wrap.setHeight("100%");
wrap.setStyleAttribute("border", "1px solid black");
wrap.add(advanced);
vp.add(wrap);
add(wrap);

advanced.setSelection(advanced.getItem(7));

}

private void addTab() {
final TabItem item = new TabItem();
item.setText("New Tab " + ++index);
item.setClosable(index != 1);
item.addText("Tab Body " + index);
item.addStyleName("pad-text");
item.setStyleAttribute("border", "1px solid green");
advanced.add(item);

addDragSupport(item);
addDropSupport(item);

}



private void addDragSupport(final TabItem tabItem) {

final HeaderItem headerItem = tabItem.getHeader();
DragSource source = new DragSource(headerItem) {
@Override
protected void onDragStart(DNDEvent event) {

event.setData(tabItem);
event.getStatus().update(headerItem.getText());

}
};
source.setGroup("DDtabs");
}

private void addDropSupport(final TabItem tabItem) {

final HeaderItem headerItem = tabItem.getHeader();
DropTarget target = new DropTarget(headerItem) {
@Override
protected void onDragDrop(DNDEvent event) {
super.onDragDrop(event);

TabItem _draggedTabItem = event.getData();
TabPanel _tabPanel = tabItem.getTabPanel();
int indexSource = _tabPanel.indexOf(_draggedTabItem);
int indexTarget = _tabPanel.indexOf(tabItem);
Info.display("source:" + indexSource, "target:" + indexTarget);

_tabPanel.insert(_draggedTabItem, indexTarget);
showAllTabHeaders(_tabPanel);
advanced.setSelection(_draggedTabItem);
}
};
target.setGroup("DDtabs");
target.setOverStyle("drag-ok");

}





private void showAllTabHeaders(TabPanel tabPanel) {
String out = "";
for (TabItem _tb : tabPanel.getItems()) {
int index = tabPanel.indexOf(_tb);
out += index + " : " + _tb.getHeader().getText() + "\n";
}
System.out.println(out);
}


}

Colin Alworth
4 Jun 2009, 2:24 PM
I think I found the issue... I've been chasing this a while, and it looks like a bug to me in TabPanel.java:422 (code below is from trunk).

416: public boolean insert(TabItem item, int index) {
417: boolean added = super.insert(item, index);
418: if (added) {
419: item.tabPanel = this;
420: item.setAutoHeight(isAutoHeight());
421: if (rendered) {
422: renderItem(item, index);At line 417, super.insert(T, int) has a routine called adjustIndex(T, int), which decrements the index by one if the item (TabItem in our case) is being inserted after itself, because by the time that happens, it will have been removed:

[tab 0] [tab 1] [tab 2]
TabPanel.add([tab 1], 2);
index will be set to 1 instead.

However, by the time we get back to TabPanel.insert(TabItem, int), we no longer have that corrected index, and the TabPanel mistakenly calls TabPanel.renderItem(TabItem, int) at 422 with the wrong index. There are a couple of fixes for this - either put the renderItem(TabItem, int) call in onInsert(T, int) where it can get the correct index, or call adjustIndex from within TabPanel.insert.

Very annoying bug, but only presents itself when moving Tabs to a later position without removing them first, but then again, you aren't supposed to have to remove the object first...

Can this be moved to the bug forum? Or should I cross post the issue and possible solutions?

sven
5 Jun 2009, 2:36 AM
I will move the part to onInsert where it gets the correct index. Will be part of the next release.

Colin Alworth
5 Jun 2009, 5:47 AM
Thanks sven - I look forward to seeing it in svn.

sven
5 Jun 2009, 6:04 AM
Fixed in SVN.