Index: org/gudy/azureus2/ui/swt/views/stats/VivaldiView.java =================================================================== RCS file: /cvsroot/azureus/azureus2/org/gudy/azureus2/ui/swt/views/stats/VivaldiView.java,v retrieving revision 1.10 diff -u -r1.10 VivaldiView.java --- org/gudy/azureus2/ui/swt/views/stats/VivaldiView.java 20 Jun 2008 17:09:59 -0000 1.10 +++ org/gudy/azureus2/ui/swt/views/stats/VivaldiView.java 23 Jun 2008 15:04:17 -0000 @@ -26,16 +26,19 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; -import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.plugins.PluginInterface; import org.gudy.azureus2.ui.swt.views.AbstractIView; import com.aelitis.azureus.core.AzureusCoreFactory; import com.aelitis.azureus.core.dht.DHT; import com.aelitis.azureus.plugins.dht.DHTPlugin; +import com.aelitis.azureus.ui.common.table.TableColumnCore; +import com.aelitis.azureus.ui.common.table.TableStructureEventDispatcher; +import com.aelitis.azureus.ui.common.table.TableStructureModificationListener; public class VivaldiView extends AbstractIView + implements TableStructureModificationListener { public static final int DHT_TYPE_MAIN = DHT.NW_MAIN; public static final int DHT_TYPE_CVS = DHT.NW_CVS; @@ -92,12 +95,24 @@ panel.setLayout(new FillLayout()); drawPanel = new VivaldiPanel(panel); drawPanel.setAutoAlpha(autoAlpha); + TableStructureEventDispatcher.getInstance(VivaldiPanel.sTableID).addListener(this); } public Composite getComposite() { return panel; } + + // ITableStructureModificationListener + public void tableStructureChanged() { + drawPanel.initializeTableColumns(); + } + // ITableStructureModificationListener stubs + public void columnOrderChanged(int[] positions) {} + public void columnSizeChanged(TableColumnCore tableColumn) {} + public void columnInvalidate(TableColumnCore tableColumn) {} + public void cellInvalidate(TableColumnCore tableColumn, Object data_source) {} + public void refresh() { if (dht == null) { init(); @@ -128,6 +143,7 @@ } public void delete() { + TableStructureEventDispatcher.getInstance(VivaldiPanel.sTableID).removeListener(this); drawPanel.delete(); super.delete(); } Index: org/gudy/azureus2/ui/swt/views/stats/VivaldiPanel.java =================================================================== RCS file: /cvsroot/azureus/azureus2/org/gudy/azureus2/ui/swt/views/stats/VivaldiPanel.java,v retrieving revision 1.29 diff -u -r1.29 VivaldiPanel.java --- org/gudy/azureus2/ui/swt/views/stats/VivaldiPanel.java 20 May 2008 21:19:35 -0000 1.29 +++ org/gudy/azureus2/ui/swt/views/stats/VivaldiPanel.java 23 Jun 2008 15:04:17 -0000 @@ -22,6 +22,7 @@ */ package org.gudy.azureus2.ui.swt.views.stats; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.eclipse.swt.SWT; @@ -33,6 +34,18 @@ import org.eclipse.swt.widgets.*; import org.gudy.azureus2.core3.internat.MessageText; +import org.gudy.azureus2.plugins.ui.tables.TableManager; +import org.gudy.azureus2.ui.swt.Messages; +import org.gudy.azureus2.ui.swt.Utils; +import org.gudy.azureus2.ui.swt.plugins.UISWTGraphic; +import org.gudy.azureus2.ui.swt.views.table.impl.FakeTableCell; +import org.gudy.azureus2.ui.swt.views.table.utils.TableColumnEditorWindow; +import org.gudy.azureus2.ui.swt.views.table.utils.TableColumnManager; +import org.gudy.azureus2.ui.swt.views.tableitems.vivaldi.IpItem; +import org.gudy.azureus2.ui.swt.views.tableitems.vivaldi.DistanceItem; +import org.gudy.azureus2.ui.swt.views.tableitems.vivaldi.ErrorItem; +import com.aelitis.azureus.ui.common.table.TableColumnCore; +import com.aelitis.azureus.ui.common.table.TableStructureEventDispatcher; import com.aelitis.azureus.core.dht.control.DHTControlContact; import com.aelitis.azureus.core.dht.transport.DHTTransportContact; @@ -61,7 +74,23 @@ private DHTTransportContact lastSelf; private Image img; - + private static final DistanceItem distanceItem = new DistanceItem(); + + /** Basic (pre-defined) Column Definitions */ + private static final TableColumnCore[] basicItems = { + distanceItem, + new ErrorItem(), + new IpItem() + }; + + /** All Column Definitions. The array is not necessarily in column order */ + private TableColumnCore[] tableColumns; + private TableColumnCore[] columnsOrdered; + private FakeTableCell[] tableCells; + + /** Context Menu */ + private Menu menu; + private int alpha = 255; private boolean autoAlpha = false; @@ -75,19 +104,20 @@ float maxX = 1000; float minY = -1000; float maxY = 1000; + double rotation = 0; float saveMinX; float saveMaxX; float saveMinY; - float saveMaxY; + float saveMaxY; + double saveRotation; public int getX(float x,float y) { - //return (int) ((x-vMinX) * vRatioX - xMinY * (y-maxY) / (maxY-minY)); - return (int) ((x-minX)/(maxX - minX) * width); + return (int) (((x * Math.cos(rotation) + y * Math.sin(rotation))-minX)/(maxX - minX) * width); } public int getY(float x,float y) { - return (int) ((y-minY)/(maxY-minY) * height); + return (int) (((y * Math.cos(rotation) - x * Math.sin(rotation))-minY)/(maxY-minY) * height); } } @@ -133,13 +163,20 @@ scale.saveMaxX = scale.maxX; scale.saveMinY = scale.minY; scale.saveMaxY = scale.maxY; + scale.saveRotation = scale.rotation; } public void mouseUp(MouseEvent event) { if(event.button == 1) mouseLeftDown = false; if(event.button == 3) mouseRightDown = false; refreshContacts(lastContacts, lastSelf); - } + int deltaX = xDown - event.x; + int deltaY = yDown - event.y; + if (event.button == 3 && Math.abs(deltaX) < 3 && Math.abs(deltaY) < 3) + { + menu.setVisible (true); + } + } }); canvas.addListener(SWT.KeyDown, new Listener() { @@ -193,6 +230,9 @@ refreshContacts(lastContacts, lastSelf); } if(mouseRightDown) { + int deltaX = event.x - xDown; + scale.rotation = scale.saveRotation - (float) deltaX / 100; + int deltaY = event.y - yDown; // scaleFactor>1 means zoom in, this happens when // deltaY<0 which happens when the mouse is moved up. @@ -230,8 +270,75 @@ } } }); + initializeColumnDefs(); + initializeTableColumns(); + this.menu = createMenu(); } - + + static final String sTableID = TableManager.TABLE_VIVALDI; + + private void initializeColumnDefs() { + // XXX Adding Columns only has to be done once per TableID. + // Doing it more than once won't harm anything, but it's a waste. + TableColumnManager tcManager = TableColumnManager.getInstance(); + if (tcManager.getTableColumnCount(sTableID) != basicItems.length) { + for (int i = 0; i < basicItems.length; i++) { + tcManager.addColumn(basicItems[i]); + } + } + + // fixup order + tcManager.ensureIntegrety(sTableID); + + tableColumns = tcManager.getAllTableColumnCoreAsArray(sTableID); + } + + protected void initializeTableColumns() { + TableColumnCore[] tmpColumnsOrdered = new TableColumnCore[tableColumns.length]; + //Create all columns + int columnOrderPos = 0; + Arrays.sort(tableColumns, TableColumnManager.getTableColumnOrderComparator()); + for (int i = 0; i < tableColumns.length; i++) { + int position = tableColumns[i].getPosition(); + if (position != -1 && tableColumns[i].isVisible()) { + tmpColumnsOrdered[columnOrderPos++] = tableColumns[i]; + } + } + columnsOrdered = new TableColumnCore[columnOrderPos]; + System.arraycopy(tmpColumnsOrdered, 0, columnsOrdered, 0, columnOrderPos); + + tableCells = new FakeTableCell[columnsOrdered.length]; + for (int i = 0; i < columnsOrdered.length; i++) { + if (columnsOrdered[i] != null) + { + tableCells[i] = new FakeTableCell(columnsOrdered[i]); + } + } + } + + /** Creates the Context Menu. + * + * @return a new Menu object + */ + public Menu createMenu() { + final Menu menu = new Menu(parent.getShell(), SWT.POP_UP); + + final MenuItem itemChangeTable = new MenuItem(menu, SWT.PUSH); + Messages.setLanguageText(itemChangeTable, + "MyTorrentsView.menu.editTableColumns"); + Utils.setMenuItemImage(itemChangeTable, "columns"); + + itemChangeTable.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + new TableColumnEditorWindow(parent.getShell(), sTableID, tableColumns, + lastSelf, + TableStructureEventDispatcher.getInstance(sTableID)); + } + }); + + return menu; + } + public void setLayoutData(Object data) { canvas.setLayoutData(data); } @@ -292,6 +399,7 @@ float ownErrorEstimate = ownPosition.getErrorEstimate(); HeightCoordinatesImpl ownCoords = (HeightCoordinatesImpl) ownPosition.getCoordinates(); + distanceItem.setOwnCoords(ownCoords); // XXX Should find a way of making our position available to all columns, probably via a custom TableCell gc.drawText("Our error: " + ownErrorEstimate,10,10); @@ -309,7 +417,7 @@ VivaldiPosition position = (VivaldiPosition)_position; HeightCoordinatesImpl coord = (HeightCoordinatesImpl) position.getCoordinates(); if(coord.isValid()) { - draw(gc,coord.getX(),coord.getY(),coord.getH(),contact,(int)ownCoords.distance(coord),position.getErrorEstimate()); + draw(gc,coord.getX(),coord.getY(),coord.getH(),contact); } } @@ -380,19 +488,41 @@ gc.drawLine(x0,y0,x0,(int)(y0-200*h/(scale.maxY-scale.minY))); } - private void draw(GC gc,float x,float y,float h,DHTControlContact contact,int distance,float error) { + private void draw(GC gc,float x,float y,float h,DHTControlContact contact) { if(x == 0 && y == 0) return; - if(error > 1) error = 1; - int errDisplay = (int) (100 * error); int x0 = scale.getX(x,y); int y0 = scale.getY(x,y); gc.fillRectangle(x0-1,y0-1,3,3); //int elevation =(int) ( 200*h/(scale.maxY-scale.minY)); //gc.drawLine(x0,y0,x0,y0-elevation); - String text = /*contact.getTransportContact().getAddress().getAddress().getHostAddress() + " (" + */distance + " ms \nerr:"+errDisplay+"%"; - int lineReturn = text.indexOf("\n"); - int xOffset = gc.getFontMetrics().getAverageCharWidth() * (lineReturn != -1 ? lineReturn:text.length()) / 2; - gc.drawText(text,x0-xOffset,y0,true); + String text = null; + for (int i = 0; i < columnsOrdered.length; i++) { + TableColumnCore tc = columnsOrdered[i]; + if (tc == null) + continue; + FakeTableCell cell = tableCells[i]; + cell.setDataSource(contact.getTransportContact()); + try { + tc.invokeCellRefreshListeners(cell, false); + } catch (Throwable e) { + } + if (cell.getText() != null) { + if (text == null) + text = cell.getText(); + else + text = text + "\n" + cell.getText(); + } + if (cell.getGraphic() != null) { + Image img = ((UISWTGraphic) cell.getGraphic()).getImage(); + Rectangle b = img.getBounds(); + gc.drawImage(img, x0 - b.width / 2, y0 - b.height); + } + } + if (text != null) { + int lineReturn = text.indexOf("\n"); + int xOffset = gc.getFontMetrics().getAverageCharWidth() * (lineReturn != -1 ? lineReturn : text.length()) / 2; + gc.drawText(text, x0 - xOffset, y0, true); + } } // Mark our own position Index: org/gudy/azureus2/internat/MessagesBundle.properties =================================================================== RCS file: /cvsroot/azureus/azureus2/org/gudy/azureus2/internat/MessagesBundle.properties,v retrieving revision 1.1056 diff -u -r1.1056 MessagesBundle.properties --- org/gudy/azureus2/internat/MessagesBundle.properties 20 Jun 2008 17:09:59 -0000 1.1056 +++ org/gudy/azureus2/internat/MessagesBundle.properties 23 Jun 2008 15:04:15 -0000 @@ -1594,6 +1594,13 @@ VivaldiView.title.full=Vivaldi VivaldiView.title.fullcvs=Vivaldi CVS VivaldiView.title.full_v6=Vivaldi IPv6 +Vivaldi.column.distance=Distance +Vivaldi.column.distance.info=The 2-dimensional delay in ms between you and the peer +Vivaldi.column.error=Error +Vivaldi.column.error.info=An weighted estimate of the error in the distance +Vivaldi.column.ip=IP +Vivaldi.column.ip.info=IP of the Peer + MyTrackerView.date_added=Added ConfigView.section.tracker.portbackup=Backup ports (';' separated) ConfigView.label.playfilespeech=Speak when a file is finished Index: org/gudy/azureus2/ui/swt/views/table/impl/FakeTableCell.java =================================================================== RCS file: /cvsroot/azureus/azureus2/org/gudy/azureus2/ui/swt/views/table/impl/FakeTableCell.java,v retrieving revision 1.12 diff -u -r1.12 FakeTableCell.java --- org/gudy/azureus2/ui/swt/views/table/impl/FakeTableCell.java 27 May 2008 21:03:26 -0000 1.12 +++ org/gudy/azureus2/ui/swt/views/table/impl/FakeTableCell.java 23 Jun 2008 15:04:18 -0000 @@ -49,6 +49,7 @@ import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTGraphicImpl; import org.gudy.azureus2.ui.swt.shells.GCStringPrinter; +import com.aelitis.azureus.core.dht.transport.DHTTransportContact; import com.aelitis.azureus.ui.common.table.TableCellCore; import com.aelitis.azureus.ui.common.table.TableColumnCore; import com.aelitis.azureus.ui.common.table.TableRowCore; @@ -405,6 +406,13 @@ } } + if (coreDataSource instanceof DHTTransportContact) { + DHTTransportContact contact = (DHTTransportContact) coreDataSource; + if (contact != null) { + return contact; // XXX Can't cache this because we re-use it for each row + } + } + return pluginDataSource; } Index: org/gudy/azureus2/plugins/ui/tables/TableManager.java =================================================================== RCS file: /cvsroot/azureus/azureus2/org/gudy/azureus2/plugins/ui/tables/TableManager.java,v retrieving revision 1.6 diff -u -r1.6 TableManager.java --- org/gudy/azureus2/plugins/ui/tables/TableManager.java 23 Sep 2007 11:57:41 -0000 1.6 +++ org/gudy/azureus2/plugins/ui/tables/TableManager.java 23 Jun 2008 15:04:16 -0000 @@ -37,6 +37,8 @@ public static final String TABLE_MYSHARES = "MyShares"; /** Visible for All Peers table */ public static final String TABLE_ALL_PEERS = "AllPeers"; + /** Visible for Vivaldi view */ + public static final String TABLE_VIVALDI = "Vivaldi"; /** Creates a column for a UI table. * In order for this object to be displayed in an Azureus UI table, the Index: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/ErrorItem.java =================================================================== RCS file: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/ErrorItem.java diff -N org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/ErrorItem.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/ErrorItem.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008 Aelitis SAS, All rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details ( see the LICENSE file ). + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * AELITIS, SAS au capital de 46,603.30 euros, + * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. + */ + +package org.gudy.azureus2.ui.swt.views.tableitems.vivaldi; + +import org.gudy.azureus2.plugins.ui.tables.TableCell; +import org.gudy.azureus2.plugins.ui.tables.TableCellRefreshListener; +import org.gudy.azureus2.plugins.ui.tables.TableManager; +import org.gudy.azureus2.ui.swt.views.table.utils.CoreTableColumn; + +import com.aelitis.azureus.core.dht.transport.DHTTransportContact; +import com.aelitis.azureus.core.dht.netcoords.DHTNetworkPosition; +import com.aelitis.azureus.core.dht.netcoords.vivaldi.ver1.VivaldiPosition; +import com.aelitis.azureus.core.dht.netcoords.vivaldi.ver1.impl.HeightCoordinatesImpl; + +/** Distance +* +* @author NormanR +* @since 3.0.?.? +*/ +public class ErrorItem + extends CoreTableColumn + implements TableCellRefreshListener +{ + public ErrorItem() { + super("error", 1, 0, TableManager.TABLE_VIVALDI); + } + + public void refresh(TableCell cell) { + DHTTransportContact contact = (DHTTransportContact)cell.getDataSource(); + DHTNetworkPosition _position = contact.getNetworkPosition(DHTNetworkPosition.POSITION_TYPE_VIVALDI_V1); + if ( _position == null ){ + return; + } + VivaldiPosition position = (VivaldiPosition)_position; + HeightCoordinatesImpl coord = (HeightCoordinatesImpl) position.getCoordinates(); + if(coord.isValid()) { + float error = position.getErrorEstimate(); + if(error > 1) error = 1; + int errDisplay = (int) (100 * error); + cell.setText("err:"+errDisplay+"%"); + } + } +} Index: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/IpItem.java =================================================================== RCS file: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/IpItem.java diff -N org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/IpItem.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/IpItem.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008 Aelitis SAS, All rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details ( see the LICENSE file ). + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * AELITIS, SAS au capital de 46,603.30 euros, + * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. + */ + +package org.gudy.azureus2.ui.swt.views.tableitems.vivaldi; + +import org.gudy.azureus2.plugins.ui.tables.TableCell; +import org.gudy.azureus2.plugins.ui.tables.TableCellRefreshListener; +import org.gudy.azureus2.plugins.ui.tables.TableManager; +import org.gudy.azureus2.ui.swt.views.table.utils.CoreTableColumn; + +import com.aelitis.azureus.core.dht.transport.DHTTransportContact; + +/** Distance +* +* @author NormanR +* @since 3.0.?.? +*/ +public class IpItem + extends CoreTableColumn + implements TableCellRefreshListener +{ + public IpItem() { + super("ip", POSITION_INVISIBLE, 0, TableManager.TABLE_VIVALDI); + } + + public void refresh(TableCell cell) { + DHTTransportContact contact = (DHTTransportContact)cell.getDataSource(); + cell.setText(contact.getAddress().getAddress().getHostAddress()); + } +} Index: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/DistanceItem.java =================================================================== RCS file: org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/DistanceItem.java diff -N org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/DistanceItem.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/gudy/azureus2/ui/swt/views/tableitems/vivaldi/DistanceItem.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008 Aelitis SAS, All rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details ( see the LICENSE file ). + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * AELITIS, SAS au capital de 46,603.30 euros, + * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. + */ + +package org.gudy.azureus2.ui.swt.views.tableitems.vivaldi; + +import org.gudy.azureus2.plugins.ui.tables.TableCell; +import org.gudy.azureus2.plugins.ui.tables.TableCellRefreshListener; +import org.gudy.azureus2.plugins.ui.tables.TableManager; +import org.gudy.azureus2.ui.swt.views.table.utils.CoreTableColumn; + +import com.aelitis.azureus.core.dht.transport.DHTTransportContact; +import com.aelitis.azureus.core.dht.netcoords.DHTNetworkPosition; +import com.aelitis.azureus.core.dht.netcoords.vivaldi.ver1.VivaldiPosition; +import com.aelitis.azureus.core.dht.netcoords.vivaldi.ver1.impl.HeightCoordinatesImpl; + +/** Distance +* +* @author NormanR +* @since 3.0.?.? +*/ +public class DistanceItem + extends CoreTableColumn + implements TableCellRefreshListener +{ + private HeightCoordinatesImpl ownCoords; + + public DistanceItem() { + super("distance", 0, 0, TableManager.TABLE_VIVALDI); + } + + public void setOwnCoords(HeightCoordinatesImpl ownCoords) { + this.ownCoords = ownCoords; + } + + public void refresh(TableCell cell) { + DHTTransportContact contact = (DHTTransportContact)cell.getDataSource(); + DHTNetworkPosition _position = contact.getNetworkPosition(DHTNetworkPosition.POSITION_TYPE_VIVALDI_V1); + if ( _position == null ){ + return; + } + VivaldiPosition position = (VivaldiPosition)_position; + HeightCoordinatesImpl coord = (HeightCoordinatesImpl) position.getCoordinates(); + if(coord.isValid()) { + cell.setText((int)ownCoords.distance(coord)+" ms"); + } + } +}