/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2009 RSSOwl Development Team **
** http://www.rssowl.org/ **
** **
** All rights reserved **
** **
** This program and the accompanying materials are made available under **
** the terms of the Eclipse Public License v1.0 which accompanies this **
** distribution, and is available at: **
** http://www.rssowl.org/legal/epl-v10.html **
** **
** A copy is found in the file epl-v10.html and important notices to the **
** license from the team is found in the textfile LICENSE.txt distributed **
** in this package. **
** **
** This copyright notice MUST APPEAR in all copies of the file! **
** **
** Contributors: **
** RSSOwl Development Team - initial API and implementation **
** **
** ********************************************************************** */
package org.rssowl.ui.internal.dialogs.preferences;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.util.LoggingSafeRunnable;
import org.rssowl.core.util.StringUtils;
import org.rssowl.ui.internal.ApplicationWorkbenchWindowAdvisor;
import org.rssowl.ui.internal.Controller;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.ShareProvider;
import org.rssowl.ui.internal.util.CColumnLayoutData;
import org.rssowl.ui.internal.util.CTable;
import org.rssowl.ui.internal.util.LayoutUtils;
import org.rssowl.ui.internal.util.CColumnLayoutData.Size;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link PreferencePage} to configure {@link ShareProvider}.
*
* @author bpasero
*/
public class SharingPreferencesPage extends PreferencePage implements IWorkbenchPreferencePage {
/** ID of the Page */
public static final String ID = "org.rssowl.ui.SharingPreferencesPage"; //$NON-NLS-1$
private LocalResourceManager fResources;
private IPreferenceScope fPreferences;
private Button fMoveDownButton;
private Button fMoveUpButton;
private CheckboxTableViewer fViewer;
private int[] fInitialShareProviderState;
/** Leave for reflection */
public SharingPreferencesPage() {
setImageDescriptor(OwlUI.getImageDescriptor("icons/elcl16/share.gif")); //$NON-NLS-1$
fResources = new LocalResourceManager(JFaceResources.getResources());
fPreferences = Owl.getPreferenceService().getGlobalScope();
}
/*
* @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
*/
public void init(IWorkbench workbench) {
fInitialShareProviderState = fPreferences.getIntegers(DefaultPreferences.SHARE_PROVIDER_STATE);
}
/*
* @see org.eclipse.jface.preference.PreferencePage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
super.createControl(parent);
updateApplyEnablement(false);
}
/*
* @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createContents(Composite parent) {
Composite container = createContainer(parent);
StyledText infoText = new StyledText(container, SWT.WRAP | SWT.READ_ONLY);
infoText.setEnabled(false);
infoText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
((GridData) infoText.getLayoutData()).widthHint = 200;
infoText.setBackground(container.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
infoText.setText(Messages.SharingPreferencesPage_SELECT_COMMUNITY);
Composite tableContainer = new Composite(container, SWT.NONE);
tableContainer.setLayout(LayoutUtils.createGridLayout(1, 0, 0));
tableContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
CTable cTable = new CTable(tableContainer, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
fViewer = new CheckboxTableViewer(cTable.getControl());
fViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fViewer.getTable().setHeaderVisible(true);
((GridData) fViewer.getTable().getLayoutData()).heightHint = fViewer.getTable().getItemHeight() * 15;
fViewer.getTable().setFocus();
fViewer.getTable().setData(ApplicationWorkbenchWindowAdvisor.FOCUSLESS_SCROLL_HOOK, new Object());
TableColumn nameCol = new TableColumn(fViewer.getTable(), SWT.NONE);
CColumnLayoutData data = new CColumnLayoutData(Size.FILL, 100);
cTable.manageColumn(nameCol, data, Messages.SharingPreferencesPage_AVAILABLE_COMMUNITIES, null, null, false, false);
/* ContentProvider returns all providers */
fViewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object inputElement) {
return Controller.getDefault().getShareProviders().toArray();
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
});
/* Label Provider */
fViewer.setLabelProvider(new CellLabelProvider() {
@Override
public void update(ViewerCell cell) {
ShareProvider provider = (ShareProvider) cell.getElement();
cell.setText(provider.getName());
if (StringUtils.isSet(provider.getIconPath()))
cell.setImage(fResources.createImage(OwlUI.getImageDescriptor(provider.getPluginId(), provider.getIconPath())));
}
});
/* Selection */
fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateMoveEnablement();
}
});
/* Drag Support */
fViewer.addDragSupport(DND.DROP_MOVE, new Transfer[] { LocalSelectionTransfer.getTransfer() }, new DragSourceAdapter() {
@Override
public void dragStart(final DragSourceEvent event) {
SafeRunnable.run(new LoggingSafeRunnable() {
public void run() throws Exception {
IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
event.doit = (selection.size() < fViewer.getTable().getItemCount());
if (event.doit) {
LocalSelectionTransfer.getTransfer().setSelection(selection);
LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & 0xFFFFFFFFL);
};
}
});
}
@Override
public void dragSetData(final DragSourceEvent event) {
SafeRunnable.run(new LoggingSafeRunnable() {
public void run() throws Exception {
if (LocalSelectionTransfer.getTransfer().isSupportedType(event.dataType))
event.data = LocalSelectionTransfer.getTransfer().getSelection();
}
});
}
@Override
public void dragFinished(DragSourceEvent event) {
SafeRunnable.run(new LoggingSafeRunnable() {
public void run() throws Exception {
LocalSelectionTransfer.getTransfer().setSelection(null);
LocalSelectionTransfer.getTransfer().setSelectionSetTime(0);
}
});
}
});
/* Drop Support */
ViewerDropAdapter dropSupport = new ViewerDropAdapter(fViewer) {
@Override
public boolean validateDrop(Object target, int operation, TransferData transferType) {
return true;
}
@Override
public boolean performDrop(Object data) {
ShareProvider target = (ShareProvider) getCurrentTarget();
if (target != null) {
onMove((StructuredSelection) data, target, getCurrentLocation());
return true;
}
return false;
}
};
dropSupport.setFeedbackEnabled(true);
dropSupport.setScrollEnabled(true);
dropSupport.setSelectionFeedbackEnabled(true);
fViewer.addDropSupport(DND.DROP_MOVE, new Transfer[] { LocalSelectionTransfer.getTransfer() }, dropSupport);
/* Set input (ignored by ContentProvider anyways) */
fViewer.setInput(this);
updateCheckedState();
/* Ensure that the first checked element is visible */
TableItem[] items = fViewer.getTable().getItems();
for (TableItem item : items) {
if (item.getChecked()) {
fViewer.getTable().showItem(item);
break;
}
}
/* Listen on Check State Changes */
fViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
ShareProvider provider = (ShareProvider) event.getElement();
provider.setEnabled(event.getChecked());
save();
fViewer.update(provider, null);
}
});
/* Container for the Buttons to Manage Providers */
Composite buttonContainer = new Composite(container, SWT.None);
buttonContainer.setLayout(LayoutUtils.createGridLayout(1, 0, 0));
buttonContainer.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false));
/* Move Provider Up */
fMoveUpButton = new Button(buttonContainer, SWT.PUSH);
fMoveUpButton.setText(Messages.SharingPreferencesPage_MOVE_UP);
fMoveUpButton.setEnabled(false);
Dialog.applyDialogFont(fMoveUpButton);
setButtonLayoutData(fMoveUpButton);
fMoveUpButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onMove(true);
}
});
/* Move Provider Down */
fMoveDownButton = new Button(buttonContainer, SWT.PUSH);
fMoveDownButton.setText(Messages.SharingPreferencesPage_MOVE_DOWN);
fMoveDownButton.setEnabled(false);
Dialog.applyDialogFont(fMoveDownButton);
setButtonLayoutData(fMoveDownButton);
fMoveDownButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onMove(false);
}
});
/* Select All */
Button selectAllButton = new Button(buttonContainer, SWT.PUSH);
selectAllButton.setText(Messages.SharingPreferencesPage_SELECT_ALL);
Dialog.applyDialogFont(selectAllButton);
setButtonLayoutData(selectAllButton);
((GridData) selectAllButton.getLayoutData()).verticalIndent = 10;
selectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onSelectAll(false);
}
});
/* De-Select All */
Button deSelectAllButton = new Button(buttonContainer, SWT.PUSH);
deSelectAllButton.setText(Messages.SharingPreferencesPage_DESELECT_ALL);
Dialog.applyDialogFont(deSelectAllButton);
setButtonLayoutData(deSelectAllButton);
deSelectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onSelectAll(true);
}
});
/* Info Container */
Composite infoContainer = new Composite(container, SWT.None);
infoContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
infoContainer.setLayout(LayoutUtils.createGridLayout(2, 0, 0));
Label infoImg = new Label(infoContainer, SWT.NONE);
infoImg.setImage(OwlUI.getImage(fResources, "icons/obj16/info.gif")); //$NON-NLS-1$
infoImg.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
Label infoTextLabel = new Label(infoContainer, SWT.WRAP);
infoTextLabel.setText(Messages.SharingPreferencesPage_COMMUNITY_INFO);
infoTextLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
applyDialogFont(container);
/* Enable Apply Button on Selection Changes */
OwlUI.runOnSelection(new Runnable() {
public void run() {
updateApplyEnablement(true);
}
}, container);
return container;
}
private Composite createContainer(Composite parent) {
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout(2, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));
composite.setFont(parent.getFont());
return composite;
}
private void onSelectAll(boolean deselect) {
TableItem[] items = fViewer.getTable().getItems();
for (int i = 0; i < items.length; i++) {
TableItem tableItem = items[i];
ShareProvider provider = (ShareProvider) tableItem.getData();
provider.setEnabled(!deselect);
fViewer.setChecked(provider, !deselect);
}
save();
fViewer.refresh();
}
private void save() {
TableItem[] items = fViewer.getTable().getItems();
int[] newState = new int[items.length];
for (int i = 0; i < items.length; i++) {
TableItem tableItem = items[i];
ShareProvider provider = (ShareProvider) tableItem.getData();
int index = provider.getIndex();
index++; //Adjust to non-zero indexing
if (!provider.isEnabled())
index = index * -1;
newState[i] = index;
}
fPreferences.putIntegers(DefaultPreferences.SHARE_PROVIDER_STATE, newState);
}
private void updateMoveEnablement() {
boolean enableMoveUp = true;
boolean enableMoveDown = true;
int[] selectionIndices = fViewer.getTable().getSelectionIndices();
if (selectionIndices.length == 1) {
enableMoveUp = selectionIndices[0] != 0;
enableMoveDown = selectionIndices[0] != fViewer.getTable().getItemCount() - 1;
} else {
enableMoveUp = false;
enableMoveDown = false;
}
fMoveUpButton.setEnabled(enableMoveUp);
fMoveDownButton.setEnabled(enableMoveDown);
}
private void onMove(boolean up) {
TableItem[] items = fViewer.getTable().getItems();
List<ShareProvider> sortedProviders = new ArrayList<ShareProvider>(items.length);
for (TableItem item : items) {
sortedProviders.add((ShareProvider) item.getData());
}
IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
ShareProvider selectedProvider = (ShareProvider) selection.getFirstElement();
int[] order = fPreferences.getIntegers(DefaultPreferences.SHARE_PROVIDER_STATE);
int selectedIndex = sortedProviders.indexOf(selectedProvider);
/* Move Up */
if (up && selectedIndex > 0) {
int order1 = order[selectedIndex];
int order2 = order[selectedIndex - 1];
order[selectedIndex] = order2;
order[selectedIndex - 1] = order1;
}
/* Move Down */
else if (!up && selectedIndex < sortedProviders.size() - 1) {
int order1 = order[selectedIndex];
int order2 = order[selectedIndex + 1];
order[selectedIndex] = order2;
order[selectedIndex + 1] = order1;
}
fPreferences.putIntegers(DefaultPreferences.SHARE_PROVIDER_STATE, order);
fViewer.refresh();
fViewer.getTable().showSelection();
updateCheckedState();
updateMoveEnablement();
}
private void onMove(StructuredSelection selection, ShareProvider destination, int location) {
/* Determine Moved Items */
List<ShareProvider> movedItems = new ArrayList<ShareProvider>();
Object[] selectedElements = selection.toArray();
for (Object element : selectedElements) {
movedItems.add((ShareProvider) element);
}
/* Determine Visible Items */
List<ShareProvider> visibleItems = new ArrayList<ShareProvider>();
TableItem[] items = fViewer.getTable().getItems();
for (TableItem item : items) {
visibleItems.add((ShareProvider) item.getData());
}
/* Return in these unlikely cases */
if (movedItems.isEmpty() || visibleItems.isEmpty())
return;
/* Remove all Moved Items from Visible */
visibleItems.removeAll(movedItems);
/* Put Moved Items to Destination Index if possible */
int destinationIndex = visibleItems.indexOf(destination);
if (destinationIndex >= 0) {
/* Adjust Destination */
if (location == ViewerDropAdapter.LOCATION_ON || location == ViewerDropAdapter.LOCATION_AFTER)
destinationIndex++;
/* Add to Visible */
visibleItems.addAll(destinationIndex, movedItems);
/* Save Visible */
int[] newState = new int[items.length];
for (int i = 0; i < visibleItems.size(); i++) {
ShareProvider provider = visibleItems.get(i);
int index = provider.getIndex();
index++; //Adjust to non-zero indexing
if (!provider.isEnabled())
index = index * -1;
newState[i] = index;
}
fPreferences.putIntegers(DefaultPreferences.SHARE_PROVIDER_STATE, newState);
/* Show Updates */
fViewer.refresh();
/* Restore Selection */
fViewer.getTable().setSelection(destinationIndex, destinationIndex + movedItems.size() - 1);
/* Update */
updateCheckedState();
updateMoveEnablement();
}
}
private void updateCheckedState() {
TableItem[] items = fViewer.getTable().getItems();
for (TableItem item : items) {
ShareProvider provider = (ShareProvider) item.getData();
fViewer.setChecked(provider, provider.isEnabled());
}
}
/*
* @see org.eclipse.jface.preference.PreferencePage#performOk()
*/
@Override
public boolean performOk() {
save();
return super.performOk();
}
/*
* @see org.eclipse.jface.preference.PreferencePage#performDefaults()
*/
@Override
protected void performDefaults() {
IPreferenceScope defaultScope = Owl.getPreferenceService().getDefaultScope();
int[] defaultState = defaultScope.getIntegers(DefaultPreferences.SHARE_PROVIDER_STATE);
Owl.getPreferenceService().getGlobalScope().putIntegers(DefaultPreferences.SHARE_PROVIDER_STATE, defaultState);
fViewer.refresh();
updateCheckedState();
updateMoveEnablement();
updateApplyEnablement(true);
}
/*
* @see org.eclipse.jface.preference.PreferencePage#performApply()
*/
@Override
protected void performApply() {
super.performApply();
fInitialShareProviderState = fPreferences.getIntegers(DefaultPreferences.SHARE_PROVIDER_STATE);
updateApplyEnablement(false);
}
/*
* @see org.eclipse.jface.preference.PreferencePage#performCancel()
*/
@Override
public boolean performCancel() {
fPreferences.putIntegers(DefaultPreferences.SHARE_PROVIDER_STATE, fInitialShareProviderState);
return super.performCancel();
}
/*
* @see org.eclipse.jface.dialogs.DialogPage#dispose()
*/
@Override
public void dispose() {
super.dispose();
fResources.dispose();
}
private void updateApplyEnablement(boolean enable) {
Button applyButton = getApplyButton();
if (applyButton != null && !applyButton.isDisposed() && applyButton.isEnabled() != enable)
applyButton.setEnabled(enable);
}
}