I have created a Custom JavaFX Control, Call it ComboBoxTablePopup, it's a Generic Control witch takes a list of items of type S from the user.
Internally, i have used some sort of filtering in the TableView(a child of ComboboxTablePopup Contrl).So i have used :
FiltredList.setPridcate(S -> {
if (pr == null || pr.isEmpty() || pr.length() == 0)
return true;
if (((Engine) S).getDesignation().toLowerCase().contains(pr.toLowerCase())) {
return true;
} else
return false;).
Because i'm using generic class and the list can be of any type i have to cast filtredlist items to well known object in ordre to get filtring work.
So, how can i make the predicate function generic, so i can work with any object and filtre it ?
Here is the code of my CustomControl:
public class ComboBoxTablePopup<S> extends ComboBoxBase {
private
ObservableList<TableColumn> columns = FXCollections.emptyObservableList();
public ObservableList<TableColumn> getColumns() {
return columns;
}
public void setColumns(ObservableList<TableColumn> columns) {
this.columns = columns;
}
/***************************************************************************
* *
* Static properties and methods *
* *
**************************************************************************/
private static <T> StringConverter<T> defaultStringConverter() {
return new StringConverter<T>() {
#Override
public String toString(T t) {
return t == null ? null : t.toString();
}
#Override
public T fromString(String string) {
return (T) string;
}
};
}
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Creates a default ComboboxTablePopup instance with an empty
* {#link #itemsProperty() items} list and default
* {#link #selectionModelProperty() selection model}.
*/
public ComboBoxTablePopup() {
this(FXCollections.<S>emptyObservableList());
}
/**
* Creates a default ComboboxTablePopup instance with the provided items list and
* a default {#link #selectionModelProperty() selection model}.
*/
public ComboBoxTablePopup(ObservableList<S> items) {
setItems(items);
getStyleClass().add(DEFAULT_STYLE_CLASS);
setEditable(true);
setPromptText("Plz Search for a pirticular term");
}
public ComboBoxTablePopup(ObservableList<S> items, ObservableList<TableColumn> columns) {
this(items);
this.columns = columns;
}
private static final String DEFAULT_STYLE_CLASS = "combobox-table-popup";
private ReadOnlyObjectWrapper<TextField> editor;
private ObjectProperty<ObservableList<S>> items = new SimpleObjectProperty<ObservableList<S>>(this, "items");
public final void setItems(ObservableList<S> value) {
itemsProperty().set(value);
}
public final ObservableList<S> getItems() {
return items.get();
}
public ObjectProperty<ObservableList<S>> itemsProperty() {
return items;
}
// Converter
public ObjectProperty<StringConverter<S>> converterProperty() {
return converter;
}
private ObjectProperty<StringConverter<S>> converter =
new SimpleObjectProperty<StringConverter<S>>(this, "converter", ComboBoxTablePopup.<S>defaultStringConverter());
public final void setConverter(StringConverter<S> value) {
converterProperty().set(value);
}
public final StringConverter<S> getConverter() {
return converterProperty().get();
}// Create a symmetric (format/parse) converter with the default locale.
// Editor
public TextField getEditor() {
return editorProperty().get();
}
public ReadOnlyObjectProperty<TextField> editorProperty() {
if (editor == null) {
editor = new ReadOnlyObjectWrapper<TextField>(this, "editor");
editor.set(new ComboBoxListViewSkin.FakeFocusTextField());
}
return editor.getReadOnlyProperty();
}
#Override
protected Skin<?> createDefaultSkin() {
return new ComboBoxTablePopupSkin<>(this);
}
}
public class ComboBoxTablePopupSkin<S> extends ComboBoxPopupControl {
private ComboBoxTablePopup comboBoxTablePopup;
private ObservableList<S> comboboxTablePopupItems;
private TextField displayNode;
private TableView<S> tableViewPopupContent;
FilteredList<S> filtredList;
private SortedList<S> sortedList;
private Predicate<S> predicate;
private final InvalidationListener itemsObserver;
private final ListChangeListener<S> tableViewItemsListener = new ListChangeListener<S>() {
#Override
public void onChanged(ListChangeListener.Change<? extends S> c) {
getSkinnable().requestLayout();
}
};
private final WeakListChangeListener<S> weakListViewItemsListener =
new WeakListChangeListener<S>(tableViewItemsListener);
public ComboBoxTablePopupSkin(ComboBoxTablePopup comboBoxTablePopup) {
super(comboBoxTablePopup, new ComboBoxTablePopupBehavior(comboBoxTablePopup));
this.comboBoxTablePopup = comboBoxTablePopup;
setupTablePredicate();
updateComboBoxTablePopupItems();
itemsObserver = observable -> {
updateComboBoxTablePopupItems();
updateTableViewItems();
};
this.comboBoxTablePopup.itemsProperty().addListener(new WeakInvalidationListener(itemsObserver));
tableViewPopupContent = createTableView();
tableViewPopupContent.setManaged(false);
getChildren().add(tableViewPopupContent);
updateTableViewItems();
getEditor().textProperty().addListener((obv, oldValue, newValue) -> {
if (!newValue.isEmpty())
comboBoxTablePopup.show();
filtreData(newValue);
});
registerChangeListener(comboBoxTablePopup.itemsProperty(), "ITEMS");
registerChangeListener(comboBoxTablePopup.valueProperty(), "VALUE");
registerChangeListener(comboBoxTablePopup.editorProperty(), "EDITABLE");
}
private void setupTablePredicate() {
}
private void updateTableViewItems() {
filtredList = new FilteredList<S>(comboboxTablePopupItems, p -> true);
sortedList = new SortedList<S>(filtredList);
sortedList.comparatorProperty().bind(tableViewPopupContent.comparatorProperty());
tableViewPopupContent.setItems(sortedList);
}
private void filtreData(String pr) {
String data = pr;
filtredList.setPredicate(engine -> {
if (pr == null || pr.isEmpty() || pr.length() == 0)
return true;
if (((Engine) engine).getDesignation().toLowerCase().contains(pr.toLowerCase())) {
return true;
} else
return false;
});
}
public void updateComboBoxTablePopupItems() {
comboboxTablePopupItems = comboBoxTablePopup.getItems();
comboboxTablePopupItems = comboboxTablePopupItems == null ? FXCollections.<S>emptyObservableList() : comboboxTablePopupItems;
}
private TableView<S> createTableView() {
final TableView<S> tableView = new TableView<>();
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
tableView.setFocusTraversable(false);
tableView.getSelectionModel().selectedItemProperty().addListener(o -> {
int index = tableView.getSelectionModel().getSelectedIndex();
System.out.println("selected item changed");
});
for (TableColumn tblColumn : tableColumns()) {
tableView.getColumns().add(tblColumn);
}
tableView.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ENTER ||
e.getCode() == KeyCode.ESCAPE ||
e.getCode() == KeyCode.SPACE) {
S selectedItem = tableView.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
System.out.println(((Engine) selectedItem).getDesignation());
getEditor().setText(((Engine) selectedItem).getDesignation());
comboBoxTablePopup.setValue(selectedItem);
comboBoxTablePopup.hide();
}
}
});
return tableView;
}
private ObservableList<TableColumn> tableColumns() {
return ((ComboBoxTablePopup) getSkinnable()).getColumns();
}
#Override
protected Node getPopupContent() {
return this.tableViewPopupContent;
}
#Override
protected TextField getEditor() {
return ((ComboBoxTablePopup) getSkinnable()).getEditor();
}
#Override
protected StringConverter getConverter() {
return ((ComboBoxTablePopup) getSkinnable()).getConverter();
}
#Override
public Node getDisplayNode() {
if (displayNode == null) {
displayNode = getEditableInputNode();
displayNode.getStylesheets().add("ComboBoxTable-display-node");
updateDisplayNode();
}
displayNode.setEditable(comboBoxTablePopup.isEditable());
return displayNode;
}
#Override
protected void handleControlPropertyChanged(String p) {
super.handleControlPropertyChanged(p);
if ("TEXT".equals(p)) {
if (!getEditor().textProperty().get().isEmpty()) {
comboBoxTablePopup.show();
}
filtreData(getEditor().textProperty().get());
} else if ("ITEMS".equals(p)) {
updateComboBoxTablePopupItems();
} else if ("EDITABLE".equals(p)) {
getEditableInputNode();
}
}
}
Use the StringConverter to convert the item to a String or use a similar property.
public class ComboBoxTablePopupSkin<S> extends ComboBoxPopupControl<S> {
...
private static final StringConverter DEFAULT_CONVERTER = new StringConverter() {
#Override
public String toString(Object o) {
return o == null ? null : o.toString();
}
#Override
public Object fromString(String s) {
throw new UnsupportedOperationException();
}
};
public final StringConverter<S> getConverter() {
StringConverter<S> converter = converterProperty().get();
// fix in case the property is set to a null
return converter == null ? DEFAULT_CONVERTER : converter;
}
private void filtreData(String pr) {
if (pr == null || pr.isEmpty()) {
filtredList.setPredicate(null);
} else {
final StringConverter<S> converter = ((ComboBoxTablePopup<S>) getSkinnable()).getConverter();
final String data = pr.toLowerCase();
filtredList.setPredicate(object -> {
String s = converter.toString(object);
return s != null && s.toLowerCase().contains(data);
});
}
}
Related
i'm trying to implement a lucene filter to remove a prefix from a term in a query.
It seems that sometime after multiple queries, the filter has been reused so the char buffer is dirty.
Code below is simplified, prefix is an external parameter.
public static class PrefixFilter extends TokenFilter {
private final PackedTokenAttributeImpl termAtt = (PackedTokenAttributeImpl) addAttribute(CharTermAttribute.class);
public PrefixFilter(TokenStream in) {
super(in);
}
#Override
public final boolean incrementToken() throws IOException {
if (!input.incrementToken()) {
return false;
}
String value = new String(termAtt.buffer());
value = value.trim();
value = value.toLowerCase();
value = StringUtils.removeStart(value, "prefix_");
if (value.isBlank()) {
termAtt.setEmpty();
} else {
termAtt.copyBuffer(value.toCharArray(), 0, value.length());
termAtt.setLength(value.length());
}
return true;
}
}
So after 10 or twelve queries, the value "prefix_a" became "abcde".
So i'm trying to add termBuffer offset end value in this way:
termAtt.setEmpty();
termAtt.resizeBuffer(value.length());
termAtt.copyBuffer(value.toCharArray(), 0, value.length());
termAtt.setLength(value.length());
termAtt.setOffset(0, value.length());
But i don't know if it's correct. Can anyone help me?
Thanks.
See if this helps you,
/**
* Standard number token filter.
*/
public class StandardnumberTokenFilter extends TokenFilter {
private final LinkedList<PackedTokenAttributeImpl> tokens;
private final StandardnumberService service;
private final Settings settings;
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private final PositionIncrementAttribute posIncAtt = addAttribute(PositionIncrementAttribute.class);
private State current;
protected StandardnumberTokenFilter(TokenStream input, StandardnumberService service, Settings settings) {
super(input);
this.tokens = new LinkedList<>();
this.service = service;
this.settings = settings;
}
#Override
public final boolean incrementToken() throws IOException {
if (!tokens.isEmpty()) {
if (current == null) {
throw new IllegalArgumentException("current is null");
}
PackedTokenAttributeImpl token = tokens.removeFirst();
restoreState(current);
termAtt.setEmpty().append(token);
posIncAtt.setPositionIncrement(0);
return true;
}
if (input.incrementToken()) {
detect();
if (!tokens.isEmpty()) {
current = captureState();
}
return true;
} else {
return false;
}
}
private void detect() throws CharacterCodingException {
CharSequence term = new String(termAtt.buffer(), 0, termAtt.length());
Collection<CharSequence> variants = service.lookup(settings, term);
for (CharSequence ch : variants) {
if (ch != null) {
PackedTokenAttributeImpl token = new PackedTokenAttributeImpl();
token.append(ch);
tokens.add(token);
}
}
}
#Override
public void reset() throws IOException {
super.reset();
tokens.clear();
current = null;
}
#Override
public boolean equals(Object object) {
return object instanceof StandardnumberTokenFilter &&
service.equals(((StandardnumberTokenFilter)object).service) &&
settings.equals(((StandardnumberTokenFilter)object).settings);
}
#Override
public int hashCode() {
return service.hashCode() ^ settings.hashCode();
}
}
https://github.com/jprante/elasticsearch-plugin-bundle/blob/f63690f877cc7f50360faffbac827622c9d404ef/src/main/java/org/xbib/elasticsearch/plugin/bundle/index/analysis/standardnumber/StandardnumberTokenFilter.java
I am new to Eclipse RCP/Plug-ins and SWT. I want to reorder table items via drag-and-drop.
I have a TableViewer which contains a table with my custom elements of type ITask (еach of my custom elements is wrapped in TableItem). All tutorials I found are about trees or dragging between different tables which is not what I need.
So I want to know how to reorder the table rows via drag-and-drop.
It's a bit long, but you can make this work in your code with a few changes. I did not included the imports; Eclipse can do it for you automatically.
I used Spring's BeanUtils class but you can use any lib (or write your own) that can deepcopy POJOs. I assume that your ITask has a setOrder(int) method and is Serializable (and it qualifies for a POJO)
You need to create a Transfer-type for your ITask: SimpleObjectTransfer is IBM's code, from Eclipse GEF. You can Google/GrepCode it.
public final class TaskTransfer extends SimpleObjectTransfer {
public static final TaskTransfer INSTANCE = new TaskTransfer();
private TaskTransfer() {
}
#Override
protected String getTypeNamePrefix() {
return "TASK_TRANSFER_FORMAT";
}
}
A ViewerDropAdapter:
public class MyDropAdapter<TM extends ITask> extends ViewerDropAdapter {
private final Class<TM> targetModelClass;
private List<TM> listOfModels;
protected MyDropAdapter(Viewer viewer, Class<TM> targetModelClass, List<TM> listOfModels) {
super(viewer);
this.listOfModels = listOfModels;
this.targetModelClass = targetModelClass;
}
#Override
public boolean performDrop(Object arg0) {
boolean ret = false;
TM targetModel = targetModelClass.cast(determineTarget(getCurrentEvent()));
if (targetModel != null) {
if (List.class.isAssignableFrom(arg0.getClass())) {
ret = processDropToTable(targetModel, arg0);
getViewer().refresh();
}
}
return ret;
}
public final boolean processDropToTable(TM targetModel, Object data) {
List<TM> transferredModels = (List<TM>) data;
List<TM> copyOfTransferredModels = transferredModels;
switch (getCurrentOperation()) {
case DND.DROP_COPY:
copyOfTransferredModels = deepCopyBeanList(transferredModels, new String[]{});
break;
case DND.DROP_MOVE:
// moving
break;
default:
throw new UnsupportedOperationException(getCurrentOperation() + " is not supported!");
}
adjustPosition(transferredModels, copyOfTransferredModels, targetModel);
return true;
}
private void adjustPosition(List<TM> transferredModels, List<TM> copyOfTransferredModels, TM targetModel) {
int transferredObjectPosition = listOfModels.indexOf(transferredModels.get(0));
listOfModels.removeAll(copyOfTransferredModels);
addModelsToNewLocation(copyOfTransferredModels, targetModel, listOfModels, transferredObjectPosition);
for (int i = 0; i < listOfModels.size(); i++) {
int orderPosition = i * 10 + 10;
listOfModels.get(i).setOrder(orderPosition);
}
}
protected void addModelsToNewLocation(List<TM> transferredModels, TM targetModel, List<TM> targetList, int transferredObjectPosition) {
switch (determineLocation(getCurrentEvent())) {
case LOCATION_AFTER:
case LOCATION_ON:
int i;
if (!transferredModels.contains(targetModel)) {
i = targetList.indexOf(targetModel) + 1;
} else {
i = transferredObjectPosition;
}
targetList.addAll(i, transferredModels);
break;
case LOCATION_BEFORE:
if (!transferredModels.contains(targetModel)) {
i = targetList.indexOf(targetModel);
} else {
i = transferredObjectPosition;
}
targetList.addAll(i, transferredModels);
break;
case LOCATION_NONE:
default:
break;
}
}
private List<TM> deepCopyBeanList(List<TM> transferredModels, String[] ignoreProperties) {
List<TM> targetList = new LinkedList<TM>();
for (TM element : transferredModels) {
try {
#SuppressWarnings("unchecked")
TM copy = (TM) element.getClass().newInstance();
BeanUtils.copyProperties(element, copy, ignoreProperties);
targetList.add(copy);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return targetList;
}
#Override
public boolean validateDrop(Object arg0, int arg1, TransferData arg2) {
boolean ret = false;
for (Transfer t : new Transfer[]{TaskTransfer.INSTANCE}) {
if (t.isSupportedType(arg2)) {
ret = true;
break;
}
}
return ret;
}
}
A DragSourceListener
public class MyDragSourceListener implements DragSourceListener {
private final Viewer dragSourceViewer;
private final boolean multiObjectsEnabled;
private final Class<?> transferrableElementClass;
private Object[] draggedObjects;
public MyDragSourceListener(Viewer dragSourceViewer, boolean multiObjectsEnabled, Class<?> transferrableElementClass) {
this.dragSourceViewer = dragSourceViewer;
this.multiObjectsEnabled = multiObjectsEnabled;
this.transferrableElementClass = transferrableElementClass;
}
#Override
public void dragStart(DragSourceEvent event) {
Control source = ((DragSource) event.getSource()).getControl();
draggedObjects = null;
if (dragSourceViewer.getControl().equals(source)) {
if (multiObjectsEnabled) {
draggedObjects = ((StructuredSelection) dragSourceViewer.getSelection()).toArray();
} else {
draggedObjects = new Object[]{((StructuredSelection) dragSourceViewer.getSelection()).getFirstElement()};
}
}
event.doit = draggedObjects.length > 0 && transferredDataIsSupported();
}
private boolean transferredDataIsSupported() {
boolean ret = true;
for (Object o : draggedObjects) {
if (o == null || !transferrableElementClass.isAssignableFrom(o.getClass())) {
ret = false;
break;
}
}
return ret;
}
#Override
public void dragSetData(DragSourceEvent event) {
event.data = Arrays.asList(draggedObjects);
}
#Override
public void dragFinished(DragSourceEvent event) {
if (event.detail != DND.DROP_NONE) {
dragSourceViewer.refresh();
}
draggedObjects = null;
}
}
And place a code somewhat like this in your View:
List<ITask> tasks = new WritableList(new ArrayList<ITask>(), ITask.class);
// Let's say tableViewerTasks is your TableViewer's name
DragSource sourceTasks = new DragSource(tblTasks, DND.DROP_MOVE);
sourceTasks.setTransfer(new Transfer[]{TaskTransfer.INSTANCE});
sourceTasks.addDragListener(new MyDragSourceListener(tableViewerTasks, true, ITask.class));
DropTarget targetTasks = new DropTarget(tblTasks, DND.DROP_MOVE);
targetTasks.setTransfer(new Transfer[]{TaskTransfer.INSTANCE});
targetTasks.addDropListener(new MyDropAdapter<ITask>(tableViewerTasks, ITask.class, tasks));
I have created a method in which i have multiple if conditions. Now i want to refactor these if conditions. What would be the best design pattern/strategy to overcome multiple if conditions?
if
(
poConfiguration.strSampleLoaderPluginClass != null
&& poConfiguration.strSampleLoaderPluginClass.equals("") == false
)
{
setSampleLoaderPluginClass(poConfiguration.strSampleLoaderPluginClass);
}
if
(
poConfiguration.strPreprocessingPluginClass != null
&& poConfiguration.strPreprocessingPluginClass.equals("") == false
)
{
setPreprocessingPluginClass(poConfiguration.strPreprocessingPluginClass);
}
if
(
poConfiguration.strFeatureExtractionPluginClass != null
&& poConfiguration.strFeatureExtractionPluginClass.equals("") == false
)
{
setFeatureExtractionPluginClass(poConfiguration.strFeatureExtractionPluginClass);
}
if
(
poConfiguration.strClassificationPluginClass != null
&& poConfiguration.strClassificationPluginClass.equals("") == false
)
{
setClassificationPluginClass(poConfiguration.strClassificationPluginClass);
}
Please share your thoughts with implementations, if possible. Thanks in advance
My first idea would be the polymorphism (Click here for more info), it depends from the concrete situation:
interface MyInterface {
public boolean checkCondition(PoConfiguration poConfiguration);
public void process(PoConfiguration poConfiguration);
}
public class SampleLoader implements MyInterface {
public boolean checkCondition(PoConfiguration poConfiguration) {
return poConfiguration.strSampleLoaderPluginClass != null
&& !poConfiguration.strSampleLoaderPluginClass.isEmpty();
}
public void process(PoConfiguration poConfiguration) {
setSampleLoaderPluginClass(poConfiguration.strSampleLoaderPluginClass);
}
}
public class ClientAPI {
public void caller() {
for (MyInterface current : this.myInterfaces) {
if (current.checkCondition(current)) {
current.process();
}
}
}
You might try something like the following:
Create a Configuration class that contains ConfigurationItems
Each ConfigurationItem would have a name, value and a default value
As an improvement, you may want to create static values for the configuration items instead of using Strings.
TestConfig main Class
package com.example.config;
public class TestConfig {
static TestConfig me;
static String[][] confSettings = {{"sampleLoader","loaderDefault"}
,{"preProcessing","preProcessingDefualt"}
,{"featureExtraction","featureExtractionDefault"}
,{"classification","classificationDefault"}
};
// Object fields
Configuration configuration;
public static void main(String[] args) {
// TODO Auto-generated method stub
me = new TestConfig();
me.doWork();
}
private void doWork() {
configuration = new Configuration();
for (int i=0; i < confSettings.length; i++) {
configuration.addConfigurationItem(confSettings[i][0], confSettings[i][1], null);
}
configuration.setConfigurationItemDefault("classification", "newValue");
System.out.println("sampleLoader = " + configuration.getConfigurationItemValue("sampleLoader"));
System.out.println("classification = " + configuration.getConfigurationItemValue("classification"));
}
}
Configuration Class
package com.example.config;
import java.util.ArrayList;
import java.util.HashMap;
public class Configuration {
// Class fields
// Object fields
HashMap<String,Integer> itemNames;
ArrayList<ConfigurationItem> items;
public Configuration() {
items = new ArrayList<ConfigurationItem>();
itemNames = new HashMap<String,Integer>();
}
public Configuration addConfigurationItem(String name, String defaultValue, String value) {
if (itemNames.containsKey(name)) {
// handle duplicate configuration item
} else {
items.add(new ConfigurationItem(name, defaultValue, value));
Integer loc = new Integer(items.size()-1);
itemNames.put(name, loc);
}
return this;
}
public void setConfigurationItemDefault(String name, String defaultValue) {
int loc = getConfigurationItemIndex(name);
if (loc > -1) {
items.get(loc).setDefaultValue(defaultValue);
}
}
public String getConfigurationItemValue(String name) {
int loc = getConfigurationItemIndex(name);
if (loc > -1) {
return items.get(loc).getValue();
} else {
// handle unknown parameter
return null;
}
}
private int getConfigurationItemIndex(String name) {
if (itemNames.containsKey(name)) {
return itemNames.get(name);
} else {
// handle unknown parameter
return -1;
}
}
}
ConfigurationItem Class
package com.example.config;
public class ConfigurationItem {
// Object fields
String name;
String value;
String defaultValue;
public ConfigurationItem(){};
public ConfigurationItem(String name, String defaultValue, String value) {
this.setName(name).setDefaultValue(defaultValue).setValue(value);
}
public ConfigurationItem setName(String name) {
this.name = name;
return this;
}
public ConfigurationItem setValue(String value) {
this.value = value;
return this;
}
public ConfigurationItem setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public String getValue() {
if (value == null || value.length() == 0) {
return defaultValue;
} else {
return value;
}
}
}
I have an object CategoryBean where are defined a list of other objects CategoryBean (its children) and another object CategoryBean (its parent).
Cloning its children is not a problem, but cloning its parent isn't working. Indeed, when I have my object A and its parent P, when I go through P and get the list of its children (where I should fine A), A has not the same reference than the child of P. The objects equal ("attributly" speaking) but are not the same.
Here is my class and its attributes :
public class CategoryBean implements Externalizable, Cloneable {
public static final boolean ACTIVE = true;
public static final boolean INACTIVE = false;
public static final int VALIDATED = 1;
public static final int NON_OBSERVED = 2;
public static final int IN_PROGRESS = 3;
public static final int PARTIEL = 4;
private String perimetre;
private CategoryBean parentCategory;
private List<CategoryBean> categoryList = new LinkedList<CategoryBean>();
protected String title;
/**
* Category validée ou non
*/
protected int state = NON_OBSERVED;
/**
* Category active ou inactive
*/
protected boolean activated = ACTIVE;
/**
* #return the parentCategory
*/
public CategoryBean getParentCategory() {
return parentCategory;
}
/**
* #param parentCategory
* the parentCategory to set
*/
public void setParentCategory(CategoryBean parentCategory) {
this.parentCategory = parentCategory;
}
/**
* #return the perimetre
*/
public String getPerimetre() {
return perimetre != null ? perimetre.trim() : null;
}
/**
* #param perimetre
* the perimetre to set
*/
public void setPerimetre(String perimetre) {
this.perimetre = perimetre != null ? perimetre.trim() : null;
}
/**
* #return the category
*/
public List<CategoryBean> getCategoryList() {
return categoryList;
}
/**
* #param category
* the category to set
*/
public void setCategoryList(List<CategoryBean> categoryList) {
this.categoryList = categoryList;
}
/**
* #return the title
*/
public String getTitle() {
return title != null ? title.trim() : null;
}
/**
* #param title
* the title to set
*/
public void setTitle(String title) {
this.title = title != null ? title.trim() : null;
}
/**
* #return the state
*/
public int getState() {
return state;
}
/**
* #param state
* the state to set
*/
public void setState(int state) {
this.state = state;
}
/**
* #return the activated
*/
public boolean isActivated() {
return activated;
}
/**
* #param activated
* the activated to set
*/
public void setActivated(boolean activated) {
this.activated = activated;
}
#Override
public int hashCode() {
if (parentCategory != null && categoryList != null && title != null) {
return parentCategory.hashCode() + categoryList.hashCode() + title.hashCode();
} else if (categoryList != null && title != null) {
return parentCategory.hashCode() + categoryList.hashCode() + title.hashCode();
} else {
return super.hashCode();
}
}
#Override
public boolean equals(Object o) {
if (o != null && o instanceof CategoryBean) {
CategoryBean o2 = (CategoryBean) o;
if (getPerimetre() != null && getTitle() != null && getParentCategory() != null) {
return getPerimetre().equals(o2.getPerimetre()) && getTitle().equals(o2.getTitle())
&& getParentCategory().equals(o2.getParentCategory());
} else if (getPerimetre() != null && getTitle() != null && getPerimetre().equals(getTitle())) {
return getPerimetre().equals(o2.getPerimetre()) && getTitle().equals(o2.getTitle());
}
}
return super.equals(o);
}
#SuppressWarnings("unchecked")
#Override
public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException {
setPerimetre((String) input.readObject());
setParentCategory((CategoryBean) input.readObject());
setCategoryList((List<CategoryBean>) input.readObject());
setTitle((String) input.readObject());
setState((Integer) input.readObject());
setActivated((Boolean) input.readObject());
}
#Override
public void writeExternal(ObjectOutput output) throws IOException {
output.writeObject(getPerimetre());
output.writeObject(getParentCategory());
output.writeObject(getCategoryList());
output.writeObject(getTitle());
output.writeObject(getState());
output.writeObject(isActivated());
}
#Override
public CategoryBean clone() throws CloneNotSupportedException {
try {
CategoryBean clone = (CategoryBean) super.clone();
clone.setPerimetre(getPerimetre());
clone.setParentCategory(getParentCategory());
List<CategoryBean> categoryListClone = null;
if (getCategoryList() != null) {
categoryListClone = new LinkedList<CategoryBean>();
for (int i = 0; i < getCategoryList().size(); i++) {
categoryListClone.add(getCategoryList().get(i).clone());
}
}
clone.setCategoryList(categoryListClone);
clone.setTitle(getTitle());
clone.setState(getState());
clone.setActivated(isActivated());
return clone;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
}
Do you know what I do wrong in the clone method ?
Thanks for you help :)
(Edit) Solution :
public CategoryBean clone() throws CloneNotSupportedException {
try {
CategoryBean clone = (CategoryBean) super.clone();
clone.setPerimetre(getPerimetre());
List<CategoryBean> categoryListClone = null;
if (getCategoryList() != null) {
categoryListClone = new LinkedList<CategoryBean>();
for (int i = 0; i < getCategoryList().size(); i++) {
CategoryBean childClone = getCategoryList().get(i).clone();
childClone.setParentCategory(clone);
categoryListClone.add(childClone);
}
}
clone.setCategoryList(categoryListClone);
clone.setTitle(getTitle());
clone.setState(getState());
clone.setActivated(isActivated());
return clone;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
I think you need to cache the parent beans already cloned during the clone operation, so that when clone.setParentCategory is called in the child, this is the cloned parent that is injected in the property...
Not sure it's crystal clear :)... so... something like this (careful, no tested !) :
#Override
public CategoryBean clone() throws CloneNotSupportedException {
return cloneRecursive(new HashMap<CategoryBean, CategoryBean>());
}
private CategoryBean cloneRecursive(Map<CategoryBean, CategoryBean> categoryBeans) throws CloneNotSupportedException {
try {
CategoryBean clone = (CategoryBean) super.clone();
categoryBeans.put(this, clone);
clone.setPerimetre(getPerimetre());
clone.setParentCategory(categoryBeans.get(getParentCategory()));
List<CategoryBean> categoryListClone = null;
if (getCategoryList() != null) {
categoryListClone = new LinkedList<CategoryBean>();
for (int i = 0; i < getCategoryList().size(); i++) {
categoryListClone.add(getCategoryList().get(i).cloneRecursive(categoryBeans));
}
}
clone.setCategoryList(categoryListClone);
clone.setTitle(getTitle());
clone.setState(getState());
clone.setActivated(isActivated());
return clone;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
I'm quite new to Java so this is probably pretty straight forward question.
I want to sort an ArrayList in the class MediaLib based on the natural order of a specified key.
I can't work out how to use my comparator (compareTo(MediaInterface, key)) which is in the Media class. Whats the best way to go about this?
package assign1;
import java.util.*;
public class Media implements MediaInterface {
private Map<String, Object> fields;
private static int compare;
public Media(String title, String format) {
fields = new TreeMap<String, Object>();
fields.put("title", title);
fields.put("format", format);
}
public Object get(String key) {
return fields.get(key);
}
public void put(String key, Object value) {
fields.put(key, value);
}
public boolean hasKeywords(String[] words, boolean combineWithAND) {
Collection<Object> values = (Collection<Object>) fields.values();
int count = 0;
int size = 0;
for (String s: words) {
for (Object o: values) {
String t = o.toString();
if (t.indexOf(s) >= 0) {
count++;
break;
}
}
size++;
}
if ((count == 0 && !combineWithAND) || (combineWithAND && (count != size))) {
return false;
}
return true;
}
public int compareTo(MediaInterface mi, String key) { //<<<<<<<------calling this!!
if (mi == null)
throw new NullPointerException();
Media m = (Media) mi;
Comparable mValue = (Comparable) m.get(key);
Comparable lValue = (Comparable) fields.get(key);
if ((mValue == null) && (lValue == null)){
return 0;
}
if ((lValue == null)){
return 1;
}
if ((mValue == null)){
return -1;
}
return (lValue).compareTo(mValue);
}
#Override
public int compareTo(MediaInterface mi) {
if (mi == null)
throw new NullPointerException();
Media m = (Media) mi;
Set<String> lSet = fields.keySet();
if (compareTo(m, "title") != 0) {
return compareTo(m, "title");
}
if (compareTo(m, "year") != 0) {
return compareTo(m, "year");
}
for (String s: lSet) {
if (compareTo(m, s) != 0) {
return compareTo(m, s);
}
}
return 0;
}
public boolean equals(Object object) {
if (object == null)
return false;
if (!(object instanceof Media))
return false;
Media m = (Media) object;
if (compareTo(m) != 0) {
return false;
}
return true;
}
}
package assign1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public class MediaLib implements Searchable {
private ArrayList<MediaInterface> media;
public MediaLib() {
media = new ArrayList<MediaInterface>();
}
#Override
public void add(MediaInterface mi) {
if (media.isEmpty()) {
media.add(mi);
}
else {
for (MediaInterface m: media) {
if (mi.equals(m)) {
return;
}
}
media.add(mi);
}
}
#Override
public boolean contains(MediaInterface mi) {
for (MediaInterface m: media) {
if (mi.equals(m)) {
return true;
}
}
return false;
}
#Override
public Collection<MediaInterface> findByKeyword(String[] words, boolean combineWithAND) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if (mi.hasKeywords(words, combineWithAND)) {
foundList.add(mi);
}
}
return foundList;
}
#Override
public Collection<MediaInterface> findByTitle(String str) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if ((mi.get("title")).equals(str)) {
foundList.add(mi);
}
}
return foundList;
}
#Override
public Collection<MediaInterface> getAllWithFormat(String formatName) {
Collection<MediaInterface> foundList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
if ((mi.get("format")).equals(formatName)) {
foundList.add(mi);
}
}
return foundList;
}
public Collection<MediaInterface> getAll() {
Collection<MediaInterface> fullList = new ArrayList<MediaInterface>();
for (MediaInterface mi: media) {
fullList.add(mi);
}
return fullList;
}
#Override
public void removeAllWithKeyword(String[] words, boolean combineWithAND) {
Collection<MediaInterface> foundList = findByKeyword(words, combineWithAND);
for (MediaInterface mi: foundList) {
media.remove(mi);
}
}
#Override
public void removeAllWithFormat(String format) {
Collection<MediaInterface> foundList = getAllWithFormat(format);
for (MediaInterface mi: foundList) {
media.remove(mi);
}
}
#Override
public void sort() {
Collections.sort(media);
}
#Override
public void sort(final String fieldName) {
Collections.sort(media, new Media.compareTo(MediaInterface, fieldName)) //<<<<<--------Trying to call compareTo()
}
}
public void parse(java.io.BufferedReader br) throws java.io.IOException {
while(br.readLine()!= null) {
Media mi = new Media(/n br.readLine(), br.readLine());
while
}
}
}
You already implement the Comparable interface in your MediaInterface class, this is a generic interface, so you then implement Comparable<MediaInterface> which will then require you to implement a method with the signature
public int compareTo(final MediaInterface other)
This is why your call to Collections.sort(media); compiles
In order to sort by a specific field name, you need to provide an instance of a Comparator, the easiest way to do this will be to create an inner class in your Media class which you can then pass into Collections.sort. For example
public class Media implements MediaInterface {
public static final class FieldComparator implements Comparator<Media> {
private final String field;
public FieldComparator(final String field) {
this.field = field;
}
public int compare(final Media a, final Media b) {
// implementation to compare a.field to b.field
}
}
}
You can then rewrite your second sort method as
#Override
public void sort(final String fieldName) {
Collections.sort(media, new Media.FieldComparator(fieldName));
}