NatTable - how to implement custom CopyDataToClipboardSerializer - nattable

in CopyDataToClipboardSerializer I need to override copiedCells variable.
I do use NatTableFactory.class where I create table, register new CopyDataCommandHandler, override table style and so on. But I do not know how to override CopyDataToClipboardSerializer. Or should I register new one and create own class?

I don't know your NatTableFactory class. So I am not sure what you are doing inside that class.
If you need a custom serializer to for example replace line breaks in a text to a space to avoid breaking the table structure, you need to create a custom implementation and use that.
class MyCopyDataCommandHandler extends CopyDataCommandHandler {
public MyCopyDataCommandHandler(SelectionLayer selectionLayer, ILayer columnHeaderLayer, ILayer rowHeaderLayer) {
super(selectionLayer, columnHeaderLayer, rowHeaderLayer);
}
#Override
protected void internalDoCommand(CopyDataToClipboardCommand command, ILayerCell[][] assembledCopiedDataStructure) {
ISerializer serializer = new MyCopyDataToClipboardSerializer(assembledCopiedDataStructure, command);
serializer.serialize();
}
}
class MyCopyDataToClipboardSerializer extends CopyDataToClipboardSerializer {
public MyCopyDataToClipboardSerializer(ILayerCell[][] copiedCells, CopyDataToClipboardCommand command) {
super(copiedCells, command);
}
#Override
protected String getTextForCell(ILayerCell cell) {
return super.getTextForCell(cell).replace('\n', ' ');
}
}
Then register the custom MyCopyDataCommandHandler like this if the headers should be exported too:
CopyDataCommandHandler copyHandler =
new MyCopyDataCommandHandler(
selectionLayer,
columnHeaderDataLayer,
rowHeaderDataLayer);
gridLayer.registerCommandHandler(copyHandler);

Related

Eclipse CDT extend AdapterFactory

I try to override the functionality of CDT ResumeAtLine, MoveToLine, RunToLine. For this reason I created a custom SuspendResumeAdapterFactory but it isn't loaded but compiles and runs without error. Do I maybe need a custom adaptableType too?
Here is the content of my plugin.xml.
<extension point="org.eclipse.core.runtime.adapters">
<factory
class="my.package.CustomSuspendResumeAdapterFactory"
adaptableType="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
<adapter type="org.eclipse.debug.core.model.ISuspendResume"/>
</factory>
</extension>
And here my CustomSuspendResumeAdapterFactory this class is reconstructed from memory not 100% sure if the syntax is correct, but I think it should be clear to see what I want to do.
package my.package;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.MoveToLine;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.ResumeAtLine;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.RunToLine;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.ISuspendResume;
public class CustomSuspendResumeAdapterFactory implements IAdapterFactory {
static class SuspendResume implements ISuspendResume, IAdaptable {
private final CustomRunToLine fRunToLine;
private final CustomMoveToLine fMoveToLine;
private final CustomResumeAtLine fResumeAtLine;
SuspendResume(IExecutionDMContext execCtx) {
fRunToLine = new CustomRunToLine(execCtx);
fMoveToLine = new CustomMoveToLine(execCtx);
fResumeAtLine = new CustomResumeAtLine(execCtx);
}
#SuppressWarnings("unchecked")
#Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isInstance(RunToLine.class)) {
System.out.println("CUSTOM RUNTOLINE");
return (T)fRunToLine;
}
if (adapter.isInstance(MoveToLine.class)) {
System.out.println("CUSTOM MOVETOLINE");
return (T)fMoveToLine;
}
if (adapter.isInstance(ResumeToLine.class)) {
System.out.println("CUSTOM RESUMEATLINE");
return (T)fResumeAtLine;
}
return null;
}
#Override
public boolean canResume() { return false; }
#Override
public boolean canSuspend() { return false; }
// This must return true because the platform
// RunToLineActionDelegate will only enable the
// action if we are suspended
#Override
public boolean isSuspended() { return true; }
#Override
public void resume() throws DebugException {}
#Override
public void suspend() throws DebugException {}
}
#SuppressWarnings("unchecked")
#Override
public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
if (ISuspendResume.class.equals(adapterType)) {
if (adaptableObject instanceof IDMVMContext) {
IExecutionDMContext execDmc = DMContexts.getAncestorOfType(
((IDMVMContext)adaptableObject).getDMContext(),
IExecutionDMContext.class);
// It only makes sense to RunToLine, MoveToLine or
// ResumeAtLine if we are dealing with a thread, not a container
if (execDmc != null && !(execDmc instanceof IContainerDMContext)) {
return (T)new SuspendResume(execDmc);
}
}
}
return null;
}
#Override
public Class<?>[] getAdapterList() {
return new Class[] { ISuspendResume.class };
}
}
Why your code is not run
You have provided a new adapter factory that converts object types that are already handled. i.e. your plugin.xml says you can convert IVMContext to ISuspendResume. But the DSF plug-in already provides such an adapter factory. If you have a new target type (like IMySpecialRunToLine) you could install a factory for that, it would take IVMContext and convert it to a IMySpecialRunToLine).
Although dated, the Eclipse Corner Article on Adapter Pattern may be useful if this is a new concept.
How to do custom Run To Line implementation
If you want to provide different implementation of Run To Line, you need to provide your own version of org.eclipse.cdt.dsf.debug.service.IRunControl2.runToLine(IExecutionDMContext, String, int, boolean, RequestMonitor). The org.eclipse.cdt.dsf.debug.internal.ui.actions.RunToLine class is simply glue to connect UI features (such as buttons/etc some provided directly, some by the core eclipse debug) to the DSF backend. i.e. if you look at what RunToLine does, all it actually does is get the IRunControl2 service and call runToLine on it.
The way to provider your own implementation of IRunControl2 is override org.eclipse.cdt.dsf.gdb.service.GdbDebugServicesFactory.createRunControlService(DsfSession) and provide your own GdbDebugServicesFactory in your custom launch delegate by overriding org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate.newServiceFactory(ILaunchConfiguration, String)
RunToLine will be triggered when the user select Run To Line from the popup menu in the editor, as per this screenshot:

One shot ChangeListener in JavaFX

Is there any way to make a listener fire once and remove itself?
for(Spec spec : specs){
spec.myProperty().addListener((obs,ov,nv) -> {
if (nv.longValue() > 0){
//do whatever
spec.myProperty().removeListener(this);
}
});
}
That code won't work. I can only think of complicated solutions to this seemingly simple problem.
How about using an anonymous inner class instead of a lambda expression?
IntegerProperty property = new SimpleIntegerProperty();
InvalidationListener listener = new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
//TODO do something
property.removeListener(this);
}
};
property.addListener(listener);
The answer was partly in the comments so I'll add my [brian] solution here.
public void someMethod(){
for(Spec spec : specs){
spec.myProperty().addListener(listener);
}
}
ChangeListener<Number> listener = new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> obs, Number ov, Number nv) {
Spec spec = (Spec)((SimpleLongProperty)obs).getBean();
spec.myProperty().removeListener(this);
}
};
Note, when I create myProperty in the Spec class I use the full constructor to specify the bean. new SimpleLongProperty(this, "myProperty", 0l);
Even doing this you still can't use a lambda to remove this.

How can I observe the changed state of model items in an ObservableList?

I have an ObservableList of model items. The model item is enabled for property binding (the setter fires a property changed event). The list is the content provider to a TableViewer which allows cell editing. I also intend to add a way of adding new rows (model items) via the TableViewer so the number of items in the list may vary with time.
So far, so good.
As this is all within an eclipse editor, I would like to know when the model gets changed. I just need one changed event from any changed model item in order to set the editor 'dirty'. I guess I could attach some kind of listener to each individual list item object but I wonder if there is a clever way to do it.
I think that I might have a solution. The following class is an inline Text editor. Changes to the model bean (all instances) are picked up using the listener added in doCreateElementObservable. My eclipse editor just needs to add its' own change listener to be kept informed.
public class InlineEditingSupport extends ObservableValueEditingSupport
{
private CellEditor cellEditor;
private String property;
private DataBindingContext dbc;
IChangeListener changeListener = new IChangeListener()
{
#Override
public void handleChange(ChangeEvent event)
{
for (ITableEditorChangeListener listener : listenersChange)
{
listener.changed();
}
}
};
public InlineEditingSupport(ColumnViewer viewer, DataBindingContext dbc, String property)
{
super(viewer, dbc);
cellEditor = new TextCellEditor((Composite) viewer.getControl());
this.property = property;
this.dbc = dbc;
}
protected CellEditor getCellEditor(Object element)
{
return cellEditor;
}
#Override
protected IObservableValue doCreateCellEditorObservable(CellEditor cellEditor)
{
return SWTObservables.observeText(cellEditor.getControl(), SWT.Modify);
}
#Override
protected IObservableValue doCreateElementObservable(Object element, ViewerCell cell)
{
IObservableValue value = BeansObservables.observeValue(element, property);
value.addChangeListener(changeListener); // ADD THIS LINE TO GET CHANGE EVENTS
return value;
}
private List<ITableEditorChangeListener> listenersChange = new ArrayList<ITableEditorChangeListener>();
public void addChangeListener(ITableEditorChangeListener listener)
{
listenersChange.remove(listener);
listenersChange.add(listener);
}
public void removeChangeListener(ITableEditorChangeListener listener)
{
listenersChange.remove(listener);
}
}

Eclipse plugin - is there any editable TreeSelection class

I am looking for a solution to make this tree selection editable in the package explorer view itself.
the idea
for example- if we click rename on any class in package explorer, it will prompt a new window to rename. This functionality is same for any class that implement TreeSelection Class.
But the Solution i am looking for is - when rename is invoked, the rename option is shown at the tree itself (like we have in Windows Explorer view)
any suggestion on how to attain this behavior on eclipse.
You don't need to have some special editable selection, you just want to make the tree editable. For this you use EditingSupport, like this (adapted from http://www.vogella.com/articles/EclipseJFaceTableAdvanced/article.html#jfacetable_editor):
public class NameEditingSupport extends EditingSupport {
private final TreeViewer viewer;
public FirstNameEditingSupport(TreeViewer viewer) {
super(viewer);
this.viewer = viewer;
}
#Override
protected CellEditor getCellEditor(Object element) {
return new TextCellEditor(viewer.getTree());
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
// return the name
}
#Override
protected void setValue(Object element, Object value) {
// update the name of your object
viewer.update(element, null);
}
}
// in the code creating the tree
treeViewer.setEditingSupport(new NameEditingSupport(treeViewer));

Creating custom ActionCell in CellTable Column

I want one of my table columns to have a deleteButton.
ActionCell<Entrata> deleteCell = new ActionCell<Entrata>("x",new Delegate<Entrata>() {
#Override
public void execute(Entrata object) {
// rpc stuff....
}
});
Ok but this line generates an error:
Column<Entrata,Entrata> deleteColumn = new Column<Entrata, Entrata>(deleteCell);
"Cannot instantiate the type Column"
What do you think?
Here you go with working code:
Assumptions:
TYPE - Is the class of the data you show in rows of Cell Table it the same because I assume you want reference to the instance of data when you going to delete it
public class DeleteColumn extends Column<TYPE, TYPE>
{
public DeleteColumn()
{
super(new ActionCell<TYPE>("Delete", new ActionCell.Delegate<TYPE>() {
#Override
public void execute(TYPE record)
{
/**
*Here you go. You got a reference to an object in a row that delete was clicked. Put your "delete" code here
*/
}
}));
}
#Override
public TYPE getValue(TYPE object)
{
return object;
}
};
From the doku:
A representation of a column in a table. The column may maintain view data for each cell on demand. New view data, if needed, is created by the cell's onBrowserEvent method, stored in the Column, and passed to future calls to Cell's
So you have to declar it something like this:
Column<String, String> colum = new Column<String, String>(null) {
#Override
public String getValue(String object) {
// TODO Auto-generated method stub
return null;
}
};
Still I don't exactly know how you implement the delete button, so it would be nice if you can give us the rest of your code.
This works
//table = initialized CellTable with content already loaded
ActionCell editCell = new ActionCell<EmployeeObject>("remove", new ActionCell.Delegate<EmployeeObject>() {
public void execute(EmployeeObject object){
List<EmployeeObject> list = new ArrayList<EmployeeObject>(table.getVisibleItems());
for(int i = 0; i < list.size(); i ++){
if(object.getFirstname().equals(list.get(i).getFirstname())){
list.remove(i);
break;
}
}
table.setRowData(list);
}
});
Column<EmployeeObject, ActionCell> editColumn = (new IdentityColumn(editCell));