tableview.java
来自「Azureus is a powerful, full-featured, cr」· Java 代码 · 共 1,316 行 · 第 1/3 页
JAVA
1,316 行
/*
* Created on 2004/Apr/18
*
* Copyright (C) 2004 Aelitis SARL, 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, SARL au capital de 30,000 euros,
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/
package org.gudy.azureus2.ui.swt.views;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.ui.tables.TableContextMenuItem;
import org.gudy.azureus2.pluginsimpl.local.ui.tables.TableContextMenuItemImpl;
import org.gudy.azureus2.ui.swt.ImageRepository;
import org.gudy.azureus2.ui.swt.Messages;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.views.table.*;
import org.gudy.azureus2.ui.swt.views.table.impl.TableRowImpl;
import org.gudy.azureus2.ui.swt.views.table.utils.*;
/** An IView with a SortableTable in it. Handles composite/menu/table creation
* and management.
*
* @author Olivier (Original PeersView/MyTorrentsView/etc code)
* @author TuxPaper
* 2004/Apr/20: Remove need for tableItemToObject
*/
public class TableView
extends AbstractIView
implements SortableTable,
ParameterListener,
ITableStructureModificationListener
{
/** TableID (from {@link TableManager}) of the table this class is
* handling. Config settings are stored with the prefix of
* "Table.<i>TableID</i>"
*/
protected String sTableID;
/** Prefix for retrieving text from the properties file (MessageText)
* Typically <i>TableID</i> + "View"
*/
protected String sPropertiesPrefix;
/** Column name to sort on if user hasn't chosen one yet
*/
protected String sDefaultSortOn;
/** 1st column gap problem (Eclipse Bug 43910). Set to true when table is
* using TableItem.setImage
*/
protected boolean bSkipFirstColumn;
/** Sets the table row's height. 0 for default height. Do NOT use when
* TableItem uses setImage
*/
protected int iCellHeight = 0;
/** Sets the icon size when the row is initialized. Any TableItem.setImage
* will use this size
*/
protected Point ptIconSize = null;
/** Basic (pre-defined) Column Definitions */
private TableColumnCore[] basicItems;
/** All Column Definitions. The array is not necessarily in column order */
private TableColumnCore[] tableColumns;
/** Composite for IView implementation */
private Composite panel;
/** Table for SortableTable implementation */
private Table table;
/** SWT style options for the creation of the Table */
private int iTableStyle;
/** Context Menu */
private Menu menu;
/** Context Menu specific to the column the mouse was on */
private Menu menuThisColumn;
/** Link DataSource to their row in the table.
* key = DataSource
* value = TableRowCore
*/
private Map objectToSortableItem;
private AEMonitor objectToSortableItem_mon = new AEMonitor( "TableView:OTSI" );
/** Sorting functions */
protected TableSorter sorter;
private boolean bSortScheduled = false;
/* position of mouse in table. Used for context menu. */
private int iMouseX = -1;
/** For updating GUI.
* Some UI objects get updating every X cycles (user configurable)
*/
private int loopFactor;
/** How often graphic cells get updated
*/
private int graphicsUpdate = COConfigurationManager.getIntParameter("Graphics Update");
/** Check Column Widths every 10 seconds on Pre 3.0RC1 on OSX if view is active.
* Other OSes can capture column width changes automatically */
private int checkColumnWidthsEvery = (Constants.isOSX && SWT.getVersion() < 3054) ?
10000 / COConfigurationManager.getIntParameter("GUI Refresh") :
0;
/**
* Main Initializer
* @param _sTableID Which table to handle (see {@link TableManager}). Config settings are stored with the prefix of "Table.<i>TableID</i>"
* @param _sPropertiesPrefix Prefix for retrieving text from the properties file (MessageText). Typically <i>TableID</i> + "View"
* @param _basicItems Column Definitions
* @param _sDefaultSortOn Column name to sort on if user hasn't chosen one yet
* @param _iTableStyle SWT style constants used when creating the table
*/
public TableView(String _sTableID,
String _sPropertiesPrefix,
TableColumnCore[] _basicItems,
String _sDefaultSortOn,
int _iTableStyle) {
sTableID = _sTableID;
basicItems = _basicItems;
sPropertiesPrefix = _sPropertiesPrefix;
sDefaultSortOn = _sDefaultSortOn;
iTableStyle = _iTableStyle;
objectToSortableItem = new HashMap();
}
/**
* Main Initializer. Table Style will be SWT.SINGLE | SWT.FULL_SELECTION
*
* @param _sTableID Which table to handle (see {@link TableManager}). Config settings are stored with the prefix of "Table.<i>TableID</i>"
* @param _sPropertiesPrefix Prefix for retrieving text from the properties file (MessageText). Typically <i>TableID</i> + "View"
* @param _basicItems Column Definitions
* @param _sDefaultSortOn Column name to sort on if user hasn't chosen one yet
*/
public TableView(String _sTableID,
String _sPropertiesPrefix,
TableColumnCore[] _basicItems,
String _sDefaultSortOn) {
this(_sTableID, _sPropertiesPrefix, _basicItems, _sDefaultSortOn,
SWT.SINGLE | SWT.FULL_SELECTION);
}
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();
for (int i = 0; i < basicItems.length; i++) {
tcManager.addColumn(basicItems[i]);
}
// fixup order
tcManager.ensureIntegrety(sTableID);
tableColumns = tcManager.getAllTableColumnCoreAsArray(sTableID);
}
/**
* This method is called when the view is instanciated, it should initialize
* all GUI components. Must NOT be blocking, or it'll freeze the whole GUI.
* Caller is the GUI Thread.
*
* @param composite the parent composite. Each view should create a child
* composite, and then use this child composite to add all elements to.
*/
public void initialize(Composite composite) {
panel = createMainPanel(composite);
menu = createMenu();
fillMenu(menu);
table = createTable();
initializeTable(table);
COConfigurationManager.addParameterListener("Graphics Update", this);
Colors.getInstance().addColorsChangedListener(this);
// So all TableView objects of the same TableID have the same columns, and column widths, etc
TableStructureEventDispatcher.getInstance(sTableID).addListener(this);
}
/** Creates a composite within the specified composite and sets its layout
* to a default FillLayout().
*
* @param composite to create your Composite under
* @return The newly created composite
*/
public Composite createMainPanel(Composite composite) {
panel = new Composite(composite,SWT.NULL);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
panel.setLayout(layout);
return panel;
}
/** Creates the Table.
*
* @return The created Table.
*/
public Table createTable() {
table = new Table(panel, iTableStyle);
table.setLayoutData(new GridData(GridData.FILL_BOTH));
return table;
}
/** Creates the legend Composite
*
* @return The created Legend Composite
*/
public Composite createLegendComposite(Color[] colors,String[] keys) {
if(colors.length != keys.length) return null;
Composite legend = new Composite(panel,SWT.NULL);
legend.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout = new GridLayout();
int numColumns = colors.length * 2;
if(numColumns > 10) numColumns = 10;
layout.numColumns = numColumns;
legend.setLayout(layout);
GridData data;
for(int i = 0 ; i < colors.length ; i++) {
Label lblColor = new Label(legend,SWT.BORDER);
lblColor.setBackground(colors[i]);
data = new GridData();
data.widthHint = 20;
data.heightHint = 10;
lblColor.setLayoutData(data);
Label lblDesc = new Label(legend,SWT.NULL);
Messages.setLanguageText(lblDesc,keys[i]);
data = new GridData();
data.widthHint = 150;
lblDesc.setLayoutData(data);
}
return legend;
}
/** Sets up the sorter, columns, and context menu.
*
* @param table Table to be initialized
*/
public void initializeTable(final Table table) {
initializeColumnDefs();
table.setLinesVisible(false);
table.setMenu(menu);
table.setData("Name", sTableID);
table.setData("TableView", this);
sorter = new TableSorter(this, sTableID, sDefaultSortOn, COConfigurationManager.getBooleanParameter( "config.style.table.sortDefaultAscending" ));
// Pre 3.0RC1 SWT on OSX doesn't call this!! :(
ControlListener resizeListener = new ControlAdapter() {
public void controlResized(ControlEvent e) {
TableColumn column = (TableColumn) e.widget;
if (column == null || column.isDisposed())
return;
TableColumnCore tc = (TableColumnCore)column.getData("TableColumnCore");
if (tc != null)
tc.setWidth(column.getWidth());
int columnNumber = table.indexOf(column);
locationChanged(columnNumber);
}
};
// Setup table
// -----------
// Add 1 to position because we make a non resizable 0-sized 1st column
// to fix the 1st column gap problem (Eclipse Bug 43910)
if (bSkipFirstColumn) {
TableColumn tc = new TableColumn(table, SWT.NULL);
tc.setWidth(0);
tc.setResizable(false);
}
//Create all columns
for (int i = 0; i < tableColumns.length; i++) {
int position = tableColumns[i].getPosition();
if (position != -1) {
new TableColumn(table, SWT.NULL);
}
}
//Assign length and titles
//We can only do it after ALL columns are created, as position (order)
//may not be in the natural order (if the user re-order the columns).
for (int i = 0; i < tableColumns.length; i++) {
int position = tableColumns[i].getPosition();
if (position == -1)
continue;
String sName = tableColumns[i].getName();
// +1 for Eclipse Bug 43910 (see above)
// user has reported a problem here with index-out-of-bounds - not sure why
// but putting in a preventative check so that hopefully the view still opens
// so they can fix it
int adjusted_position = position + (bSkipFirstColumn ? 1 : 0);
if ( adjusted_position >= table.getColumnCount()){
Debug.out( "Incorrect table column setup, skipping column '" + sName + "'" );
continue;
}
TableColumn column = table.getColumn(adjusted_position);
Messages.setLanguageText(column, tableColumns[i].getTitleLanguageKey());
column.setAlignment(tableColumns[i].getSWTAlign());
column.setWidth(tableColumns[i].getWidth());
column.setData("TableColumnCore", tableColumns[i]);
column.setData("configName", "Table." + sTableID + "." + sName);
column.setData("Name", sName);
column.addControlListener(resizeListener);
// At the time of writing this SWT (3.0RC1) on OSX doesn't call the
// selection listener for tables
column.addListener(SWT.Selection, new ColumnListener(tableColumns[i]));
}
table.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
if(event.width == 0 || event.height == 0) return;
doPaint(event.gc);
}
});
// Deselect rows if user clicks on a black spot (a spot with no row)
table.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
iMouseX = e.x;
try {
if (table.getItemCount() <= 0)
return;
// skip if outside client area (ie. scrollbars)
Rectangle rTableArea = table.getClientArea();
//System.out.println("Mouse="+iMouseX+"x"+e.y+";TableArea="+rTableArea);
Point pMousePosition = new Point(e.x, e.y);
if (rTableArea.contains(pMousePosition)) {
TableItem ti = table.getItem(table.getItemCount() - 1);
Rectangle cellBounds = ti.getBounds(table.getColumnCount() - 1);
// OSX returns 0 size if the cell is not on screen (sometimes? all the time?)
if (cellBounds.width <= 0 || cellBounds.height <= 0)
return;
//System.out.println("cellbounds="+cellBounds);
if (e.x > cellBounds.x + cellBounds.width ||
e.y > cellBounds.y + cellBounds.height) {
table.deselectAll();
}
/* // This doesn't work because of OS inconsistencies when table is scrolled
// Re-enable once SWT fixes the problem
TableItem ti = table.getItem(pMousePosition);
if (ti == null)
table.deselectAll();
*/
}
} catch (Exception ex) {
System.out.println("MouseDownError");
Debug.printStackTrace( ex );
}
}
});
// XXX this may not be needed if all platforms process mouseDown
// before the menu
table.addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent e) {
iMouseX = e.x;
}
});
// Implement a "fake" tooltip
final Listener labelListener = new Listener () {
public void handleEvent (Event event) {
Shell shell;
if (event.widget instanceof Control)
shell = ((Control)event.widget).getShell();
else
shell = (Shell)event.widget;
switch (event.type) {
case SWT.MouseDown:
case SWT.MouseDoubleClick:
Event e = new Event ();
TableItem ti = (TableItem)shell.getData("_TABLEITEM");
if (!ti.isDisposed()) {
e.item = ti;
table.setSelection(table.indexOf(ti));
table.notifyListeners((event.type == SWT.MouseDown) ? SWT.Selection : SWT.DefaultSelection, e);
}
if (table != null && !table.isDisposed())
table.setFocus();
// fall through
case SWT.MouseMove:
case SWT.MouseExit:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?