package com.aelitis.azureus.ui.swt.mdi;
import java.util.LinkedList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Adapter;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.plugins.ui.UIInstance;
import org.gudy.azureus2.plugins.ui.UIManager;
import org.gudy.azureus2.plugins.ui.UIManagerListener;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.plugins.PluginUISWTSkinObject;
import org.gudy.azureus2.ui.swt.plugins.UISWTInstance;
import org.gudy.azureus2.ui.swt.plugins.UISWTViewEventListener;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore;
import org.gudy.azureus2.ui.swt.views.IViewAlwaysInitialize;
import com.aelitis.azureus.ui.UIFunctionsManager;
import com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo;
import com.aelitis.azureus.ui.mdi.MdiEntry;
import com.aelitis.azureus.ui.swt.skin.SWTSkinObject;
import com.aelitis.azureus.ui.swt.skin.SWTSkinObjectTabFolder;
import com.aelitis.azureus.ui.swt.utils.ColorCache;
public class TabbedMDI
extends BaseMDI
implements AEDiagnosticsEvidenceGenerator
{
private CTabFolder tabFolder;
private LinkedList<MdiEntry> select_history = new LinkedList<MdiEntry>();
public TabbedMDI() {
super();
AEDiagnostics.addEvidenceGenerator(this);
}
public Object skinObjectCreated(SWTSkinObject skinObject, Object params) {
super.skinObjectCreated(skinObject, params);
creatMDI();
try {
UIFunctionsManager.getUIFunctions().getUIUpdater().addUpdater(this);
} catch (Exception e) {
Debug.out(e);
}
return null;
}
// @see com.aelitis.azureus.ui.swt.mdi.BaseMDI#skinObjectInitialShow(com.aelitis.azureus.ui.swt.skin.SWTSkinObject, java.lang.Object)
public Object skinObjectInitialShow(SWTSkinObject skinObject, Object params) {
UIManager ui_manager = PluginInitializer.getDefaultInterface().getUIManager();
ui_manager.addUIListener(new UIManagerListener() {
public void UIDetached(UIInstance instance) {
}
public void UIAttached(UIInstance instance) {
if (instance instanceof UISWTInstance) {
final AESemaphore wait_sem = new AESemaphore( "TabbedMDI:wait" );
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
try{
try {
loadCloseables();
} catch (Throwable t) {
Debug.out(t);
}
setupPluginViews();
}finally{
wait_sem.release();
}
}
});
// we need to wait for the loadCloseables to complete as there is code in MainMDISetup that runs on the 'UIAttachedComplete'
// callback that needs the closables to be loaded (when setting 'start tab') otherwise the order gets broken
if ( !wait_sem.reserve(10*1000)){
Debug.out( "eh?");
}
}
}
});
return super.skinObjectInitialShow(skinObject, params);
}
private void creatMDI() {
if (soMain instanceof SWTSkinObjectTabFolder) {
tabFolder = ((SWTSkinObjectTabFolder) soMain).getTabFolder();
} else {
tabFolder = new CTabFolder((Composite) soMain.getControl(), SWT.TOP
| SWT.BORDER | SWT.CLOSE);
}
COConfigurationManager.addAndFireParameterListener("GUI_SWT_bFancyTab",
new ParameterListener() {
public void parameterChanged(String parameterName) {
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
boolean simple = !COConfigurationManager.getBooleanParameter("GUI_SWT_bFancyTab");
tabFolder.setSimple(simple);
}
});
}
});
Display display = tabFolder.getDisplay();
float[] hsb = tabFolder.getBackground().getRGB().getHSB();
hsb[2] *= (Constants.isOSX) ? 0.9 : 0.97;
tabFolder.setBackground(ColorCache.getColor(display, hsb));
hsb = tabFolder.getForeground().getRGB().getHSB();
hsb[2] *= (Constants.isOSX) ? 1.1 : 0.03;
tabFolder.setForeground(ColorCache.getColor(display, hsb));
tabFolder.setSelectionBackground(new Color[] {
display.getSystemColor(SWT.COLOR_LIST_BACKGROUND),
display.getSystemColor(SWT.COLOR_LIST_BACKGROUND),
display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)
}, new int[] {
10,
90
}, true);
tabFolder.setSelectionForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
tabFolder.setSimple(!COConfigurationManager.getBooleanParameter("GUI_SWT_bFancyTab"));
tabFolder.setMinimumCharacters(25);
tabFolder.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
TabbedEntry entry = (TabbedEntry) event.item.getData("TabbedEntry");
showEntry(entry);
}
});
tabFolder.addCTabFolder2Listener(
new CTabFolder2Adapter()
{
@Override
public void
close(
CTabFolderEvent event )
{
final TabbedEntry entry = (TabbedEntry) event.item.getData("TabbedEntry");
if ( select_history.remove( entry )){
if ( select_history.size() > 0 ){
MdiEntry next = select_history.getLast();
if ( !next.isDisposed() && next != entry ){
event.doit = false;
showEntry( next );
Utils.execSWTThreadLater(
0,
new AERunnable()
{
public void
runSupport()
{
entry.close( true );
}
});
}
}
}
}
});
tabFolder.getDisplay().addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
if ( tabFolder.isDisposed()){
return;
}
// Another window has control, skip filter
Control focus_control = tabFolder.getDisplay().getFocusControl();
if (focus_control != null
&& focus_control.getShell() != tabFolder.getShell()) {
return;
}
int key = event.character;
if ((event.stateMask & SWT.MOD1) != 0 && event.character <= 26
&& event.character > 0)
key += 'a' - 1;
// ESC or CTRL+F4 closes current Tab
if (key == SWT.ESC
|| (event.keyCode == SWT.F4 && event.stateMask == SWT.CTRL)) {
MdiEntry entry = getCurrentEntry();
if (entry != null) {
entry.close(false);
}
event.doit = false;
} else if (event.keyCode == SWT.F6
|| (event.character == SWT.TAB && (event.stateMask & SWT.CTRL) != 0)) {
// F6 or Ctrl-Tab selects next Tab
// On Windows the tab key will not reach this filter, as it is
// processed by the traversal TRAVERSE_TAB_NEXT. It's unknown
// what other OSes do, so the code is here in case we get TAB
if ((event.stateMask & SWT.SHIFT) == 0) {
event.doit = false;
selectNextTab(true);
// Shift+F6 or Ctrl+Shift+Tab selects previous Tab
} else if (event.stateMask == SWT.SHIFT) {
selectNextTab(false);
event.doit = false;
}
}
}
});
tabFolder.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
saveCloseables();
}
});
}
private void selectNextTab(boolean selectNext) {
if (tabFolder == null || tabFolder.isDisposed()) {
return;
}
final int nextOrPrevious = selectNext ? 1 : -1;
int index = tabFolder.getSelectionIndex() + nextOrPrevious;
if (index == 0 && selectNext || index == -2 || tabFolder.getItemCount() < 2) {
return;
}
if (index == tabFolder.getItemCount()) {
index = 0;
} else if (index < 0) {
index = tabFolder.getItemCount() - 1;
}
// instead of .setSelection, use showEntry which will ensure view de/activations
CTabItem item = tabFolder.getItem(index);
MdiEntry entry = (MdiEntry) item.getData("TabbedEntry");
if (entry != null) {
showEntry(entry);
}
}
protected boolean wasEntryLoadedOnce(String id) {
@SuppressWarnings("deprecation")
boolean loadedOnce = COConfigurationManager.getBooleanParameter("tab.once."
+ id, false);
return loadedOnce;
}
protected void setEntryLoadedOnce(String id) {
COConfigurationManager.setParameter("tab.once." + id, true);
}
public void showEntry(final MdiEntry newEntry) {
if (newEntry == null) {
return;
}
select_history.remove( newEntry );
select_history.add( newEntry );
if ( select_history.size() > 64 ){
select_history.removeFirst();
}
MdiEntry oldEntry = currentEntry;
if (newEntry == oldEntry) {
triggerSelectionListener(newEntry, newEntry);
return;
}
if (oldEntry != null) {
oldEntry.hide();
}
currentEntry = (MdiEntrySWT) newEntry; // assumed MdiEntrySWT
((BaseMdiEntry) newEntry).show();
triggerSelectionListener(newEntry, oldEntry);
}
public void updateUI() {
MdiEntry currentEntry = getCurrentEntry();
if (currentEntry != null) {
currentEntry.updateUI();
}
}
private MdiEntry createEntryFromSkinRef(String parentID, String id,
String configID, String title, ViewTitleInfo titleInfo, Object params,
boolean closeable, int index) {
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
return oldEntry;
}
TabbedEntry entry = new TabbedEntry(this, skin, id);
entry.setTitle(title);
entry.setSkinRef(configID, params);
setupNewEntry(entry, id, index);
return entry;
}
// @see com.aelitis.azureus.ui.swt.mdi.BaseMDI#createEntryFromSkinRef(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo, java.lang.Object, boolean, java.lang.String)
public MdiEntry createEntryFromSkinRef(String parentID, String id,
String configID, String title, ViewTitleInfo titleInfo, Object params,
boolean closeable, String preferedAfterID) {
// afterid not fully supported yet
return createEntryFromSkinRef(parentID, id, configID, title, titleInfo,
params, closeable, "".equals(preferedAfterID) ? 0 : -1);
}
public MdiEntry createEntryFromEventListener(String parentID,
UISWTViewEventListener l, String id, boolean closeable, Object datasource, String preferredAfterID) {
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
return oldEntry;
}
TabbedEntry entry = new TabbedEntry(this, skin, id);
entry.setDatasource(datasource);
entry.setPreferredAfterID(preferredAfterID);
entry.setEventListener(l);
setupNewEntry(entry, id, -1);
if (l instanceof IViewAlwaysInitialize) {
entry.build();
}
return entry;
}
public MdiEntry createEntryFromView(String parentID, UISWTViewCore view,
String id, Object datasource, boolean closeable, boolean show,
boolean expand) {
if (id == null) {
id = view.getClass().getName();
int i = id.lastIndexOf('.');
if (i > 0) {
id = id.substring(i + 1);
}
}
MdiEntry oldEntry = getEntry(id);
if (oldEntry != null) {
if (show) {
showEntry(oldEntry);
}
return oldEntry;
}
TabbedEntry entry = new TabbedEntry(this, skin, id);
entry.setCoreView(view);
entry.setDatasource(datasource);
setupNewEntry(entry, id, -1);
if (view instanceof IViewAlwaysInitialize) {
entry.build();
}
if (show) {
showEntry(entry);
}
return entry;
}
private void setupNewEntry(final TabbedEntry entry, final String id,
final int index) {
synchronized (mapIdToEntry) {
mapIdToEntry.put(id, entry);
}
entry.setCloseable(true);
Utils.execSWTThreadLater(0, new AERunnable() {
public void runSupport() {
swt_setupNewEntry(entry, id, index);
}
});
}
private void swt_setupNewEntry(TabbedEntry entry, String id, int index) {
if (index < 0 || index >= tabFolder.getItemCount()) {
index = tabFolder.getItemCount();
}
CTabItem cTabItem = new CTabItem(tabFolder, SWT.CLOSE, index);
cTabItem.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
if (tabFolder.getItemCount() == 0) {
currentEntry = null;
}
}
});
cTabItem.setData("TabbedEntry", entry);
entry.setSwtItem(cTabItem);
}
public String getUpdateUIName() {
String name = "MDI";
MdiEntry entry = getCurrentEntry();
if (entry != null) {
name += "-" + entry.getId();
}
return name;
}
public void generate(IndentWriter writer) {
MdiEntrySWT[] entries = getEntriesSWT();
for (MdiEntrySWT entry : entries) {
if (entry == null) {
continue;
}
UISWTViewCore view = entry.getCoreView();
if (!(view instanceof AEDiagnosticsEvidenceGenerator)) {
writer.println("TabbedMdi View (No Generator): " + entry.getId());
try {
writer.indent();
writer.println("Parent: " + entry.getParentID());
writer.println("Title: " + entry.getTitle());
} catch (Exception e) {
} finally {
writer.exdent();
}
}
}
}
// @see com.aelitis.azureus.ui.swt.mdi.MultipleDocumentInterfaceSWT#getEntryFromSkinObject(org.gudy.azureus2.ui.swt.plugins.PluginUISWTSkinObject)
public MdiEntrySWT getEntryFromSkinObject(PluginUISWTSkinObject pluginSkinObject) {
if (pluginSkinObject instanceof SWTSkinObject) {
Control control = ((SWTSkinObject) pluginSkinObject).getControl();
while (control != null && !control.isDisposed()) {
Object entry = control.getData("BaseMDIEntry");
if (entry instanceof BaseMdiEntry) {
BaseMdiEntry mdiEntry = (BaseMdiEntry) entry;
return mdiEntry;
}
control = control.getParent();
}
}
return null;
}
public MdiEntry createHeader(String id, String title, String preferredAfterID) {
return null;
}
}