diff --git a/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java b/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java
index 633b479e..07b2ad39 100644
--- a/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java
+++ b/diylc/diylc-core/src/org/diylc/common/PropertyWrapper.java
@@ -1,8 +1,10 @@
package org.diylc.common;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import org.diylc.core.IPropertyValidator;
+import org.diylc.core.annotations.EditableProperty;
/**
* Entity class for editable properties extracted from component objects. Represents a single
@@ -21,9 +23,12 @@ public class PropertyWrapper implements Cloneable {
private IPropertyValidator validator;
private boolean unique = true;
private boolean changed = false;
+ private String additionalOptions;
+ private int sortOrder;
+ private String[] listItems;
public PropertyWrapper(String name, Class> type, String getter, String setter, boolean defaultable,
- IPropertyValidator validator) {
+ IPropertyValidator validator, String additionalOptions, int sortOrder) {
super();
this.name = name;
this.type = type;
@@ -31,11 +36,18 @@ public class PropertyWrapper implements Cloneable {
this.setter = setter;
this.defaultable = defaultable;
this.validator = validator;
+ this.additionalOptions = additionalOptions;
+ this.sortOrder = sortOrder;
}
public void readFrom(Object object) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException {
this.value = object.getClass().getMethod(getter).invoke(object);
+ if (additionalOptions.startsWith(EditableProperty.DYNAMIC_LIST)) {
+ String functionName = additionalOptions.substring(EditableProperty.DYNAMIC_LIST.length());
+ Method listMethod = object.getClass().getMethod(functionName);
+ listItems = (String[]) listMethod.invoke(object);
+ }
}
// public void readUniqueFrom(IDIYComponent component)
@@ -92,6 +104,22 @@ public class PropertyWrapper implements Cloneable {
this.changed = changed;
}
+ public String getAdditionalOptions() {
+ return additionalOptions;
+ }
+
+ public int getSortOrder() {
+ return sortOrder;
+ }
+
+ public String[] getListItems() {
+ return listItems;
+ }
+
+ public void setOptions(String[] listItems) {
+ this.listItems = listItems;
+ }
+
// @Override
// public Object clone() throws CloneNotSupportedException {
// // Try to invoke clone method on value if possible.
@@ -105,7 +133,8 @@ public class PropertyWrapper implements Cloneable {
@Override
public Object clone() throws CloneNotSupportedException {
PropertyWrapper clone =
- new PropertyWrapper(this.name, this.type, this.getter, this.setter, this.defaultable, this.validator);
+ new PropertyWrapper(this.name, this.type, this.getter, this.setter, this.defaultable, this.validator,
+ this.additionalOptions, this.sortOrder);
clone.value = this.value;
clone.changed = this.changed;
clone.unique = this.unique;
@@ -116,11 +145,11 @@ public class PropertyWrapper implements Cloneable {
public int hashCode() {
final int prime = 31;
int result = 1;
+ result = prime * result + ((additionalOptions == null) ? 0 : additionalOptions.hashCode());
result = prime * result + (defaultable ? 1231 : 1237);
result = prime * result + ((getter == null) ? 0 : getter.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((setter == null) ? 0 : setter.hashCode());
- result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@@ -133,6 +162,11 @@ public class PropertyWrapper implements Cloneable {
if (getClass() != obj.getClass())
return false;
PropertyWrapper other = (PropertyWrapper) obj;
+ if (additionalOptions == null) {
+ if (other.additionalOptions != null)
+ return false;
+ } else if (!additionalOptions.equals(other.additionalOptions))
+ return false;
if (defaultable != other.defaultable)
return false;
if (getter == null) {
diff --git a/diylc/diylc-core/src/org/diylc/core/Project.java b/diylc/diylc-core/src/org/diylc/core/Project.java
index 68aab3c4..cfcdb30a 100644
--- a/diylc/diylc-core/src/org/diylc/core/Project.java
+++ b/diylc/diylc-core/src/org/diylc/core/Project.java
@@ -54,7 +54,7 @@ public class Project implements Serializable {
gridSpacing = DEFAULT_GRID_SPACING;
}
- @EditableProperty(defaultable = false)
+ @EditableProperty(defaultable = false, sortOrder = 1)
public String getTitle() {
return title;
}
@@ -63,7 +63,7 @@ public class Project implements Serializable {
this.title = title;
}
- @EditableProperty
+ @EditableProperty(sortOrder = 3)
public String getAuthor() {
return author;
}
@@ -72,7 +72,7 @@ public class Project implements Serializable {
this.author = author;
}
- @EditableProperty(defaultable = false)
+ @EditableProperty(defaultable = false, additionalOptions = EditableProperty.MULTI_LINE, sortOrder = 2)
public String getDescription() {
return description;
}
@@ -81,7 +81,7 @@ public class Project implements Serializable {
this.description = description;
}
- @EditableProperty
+ @EditableProperty(sortOrder = 4)
public Size getWidth() {
return width;
}
@@ -90,7 +90,7 @@ public class Project implements Serializable {
this.width = width;
}
- @EditableProperty
+ @EditableProperty(sortOrder = 5)
public Size getHeight() {
return height;
}
@@ -99,7 +99,7 @@ public class Project implements Serializable {
this.height = height;
}
- @EditableProperty(name = "Grid spacing", validatorClass = SpacingValidator.class)
+ @EditableProperty(name = "Grid spacing", validatorClass = SpacingValidator.class, sortOrder = 6)
public Size getGridSpacing() {
return gridSpacing;
}
diff --git a/diylc/diylc-core/src/org/diylc/core/annotations/EditableProperty.java b/diylc/diylc-core/src/org/diylc/core/annotations/EditableProperty.java
index cd87d4d0..9bc60eeb 100644
--- a/diylc/diylc-core/src/org/diylc/core/annotations/EditableProperty.java
+++ b/diylc/diylc-core/src/org/diylc/core/annotations/EditableProperty.java
@@ -16,6 +16,18 @@ import org.diylc.core.IPropertyValidator;
@Retention(RetentionPolicy.RUNTIME)
public @interface EditableProperty {
+ /**
+ * Used to designate that a {@link String} property can have multi-lined text.
+ */
+ public static final String MULTI_LINE = "MULTI-LINE";
+ /**
+ * Used when property can have one of the values from a dynamic list. In such cases,
+ * {@link EditableProperty#additionalOptions()} should begin with
+ * {@link EditableProperty#DYNAMIC_LIST} and contain a method name from the parent object that
+ * should be called to obtain the {@link String} array with possible options.
+ */
+ public static final String DYNAMIC_LIST = "DYNAMIC_LIST:";
+
/**
* Returns property name. If left blank property name will be extracted from the getter name, e.g.
* getter getXYZ will induce property name XYZ.
@@ -39,4 +51,19 @@ public @interface EditableProperty {
* @return
*/
Class extends IPropertyValidator> validatorClass() default AllowAllValidator.class;
+
+ /**
+ * Optional parameter in case we want to force an order of properties.
+ *
+ * @return
+ */
+ int sortOrder() default Integer.MAX_VALUE;
+
+ /**
+ * Optional parameter for properties that require additional configuration. This will be passed
+ * down to the editor factory.
+ *
+ * @return
+ */
+ String additionalOptions() default "";
}
diff --git a/diylc/diylc-core/src/org/diylc/plugins/cloud/model/ProjectEntity.java b/diylc/diylc-core/src/org/diylc/plugins/cloud/model/ProjectEntity.java
index 5188f55f..291a63ca 100644
--- a/diylc/diylc-core/src/org/diylc/plugins/cloud/model/ProjectEntity.java
+++ b/diylc/diylc-core/src/org/diylc/plugins/cloud/model/ProjectEntity.java
@@ -2,6 +2,8 @@ package org.diylc.plugins.cloud.model;
import java.io.Serializable;
+import org.diylc.core.annotations.EditableProperty;
+
public class ProjectEntity implements Serializable {
private static final long serialVersionUID = 1L;
@@ -11,12 +13,15 @@ public class ProjectEntity implements Serializable {
private String description;
private String owner;
private String category;
+ private String categoryForDisplay;
private String updated;
private String thumbnailUrl;
private String downloadUrl;
+ private String keywords;
private int viewCount;
private int downloadCount;
private int commentCount;
+ private String[] categories;
public ProjectEntity() {
super();
@@ -30,6 +35,7 @@ public class ProjectEntity implements Serializable {
this.id = id;
}
+ @EditableProperty(defaultable = false, sortOrder = 1)
public String getName() {
return name;
}
@@ -38,6 +44,7 @@ public class ProjectEntity implements Serializable {
this.name = name;
}
+ @EditableProperty(defaultable = false, additionalOptions = EditableProperty.MULTI_LINE, sortOrder = 3)
public String getDescription() {
return description;
}
@@ -53,7 +60,7 @@ public class ProjectEntity implements Serializable {
public void setOwner(String owner) {
this.owner = owner;
}
-
+
public String getCategory() {
return category;
}
@@ -61,6 +68,23 @@ public class ProjectEntity implements Serializable {
public void setCategory(String category) {
this.category = category;
}
+
+ @EditableProperty(defaultable = false, sortOrder = 2, additionalOptions = EditableProperty.DYNAMIC_LIST + "getCategories")
+ public String getCategoryForDisplay() {
+ return categoryForDisplay;
+ }
+
+ public void setCategoryForDisplay(String categoryForDisplay) {
+ this.categoryForDisplay = categoryForDisplay;
+ }
+
+ public String[] getCategories() {
+ return categories;
+ }
+
+ public void setCategories(String[] categories) {
+ this.categories = categories;
+ }
public String getUpdated() {
return updated;
@@ -110,6 +134,15 @@ public class ProjectEntity implements Serializable {
this.commentCount = commentCount;
}
+ @EditableProperty(defaultable = false, sortOrder = 4)
+ public String getKeywords() {
+ return keywords;
+ }
+
+ public void setKeywords(String keywords) {
+ this.keywords = keywords;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -120,6 +153,7 @@ public class ProjectEntity implements Serializable {
result = prime * result + downloadCount;
result = prime * result + ((downloadUrl == null) ? 0 : downloadUrl.hashCode());
result = prime * result + id;
+ result = prime * result + ((keywords == null) ? 0 : keywords.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((thumbnailUrl == null) ? 0 : thumbnailUrl.hashCode());
@@ -158,6 +192,11 @@ public class ProjectEntity implements Serializable {
return false;
if (id != other.id)
return false;
+ if (keywords == null) {
+ if (other.keywords != null)
+ return false;
+ } else if (!keywords.equals(other.keywords))
+ return false;
if (name == null) {
if (other.name != null)
return false;
diff --git a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java
index ce9019a2..2dd7c8b2 100644
--- a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java
+++ b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java
@@ -8,14 +8,18 @@ import java.net.NetworkInterface;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
+import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
+import org.diylc.common.PropertyWrapper;
import org.diylc.plugins.cloud.model.CommentEntity;
import org.diylc.plugins.cloud.model.IServiceAPI;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.model.UserEntity;
+import org.diylc.presenter.ComparatorFactory;
+import org.diylc.presenter.ComponentProcessor;
import com.diyfever.httpproxy.PhpFlatProxy;
import com.diyfever.httpproxy.ProxyFactory;
@@ -153,6 +157,24 @@ public class CloudPresenter {
}
}
+ public void updateProjectDetails(ProjectEntity project, String diylcVersion) throws IOException, CloudException {
+ String username = ConfigurationManager.getInstance().readString(USERNAME_KEY, null);
+ String token = ConfigurationManager.getInstance().readString(TOKEN_KEY, null);
+
+ if (username == null || token == null)
+ throw new CloudException("Login failed. Please try to login again.");
+
+ try {
+ String res =
+ getService().uploadProject(username, token, getMachineId(), project.getName(), project.getCategoryForDisplay(),
+ project.getDescription(), diylcVersion, project.getKeywords(), null, null, project.getId());
+ if (!res.equals(SUCCESS))
+ throw new CloudException(res);
+ } catch (Exception e) {
+ throw new CloudException(e);
+ }
+ }
+
public void deleteProject(int projectId) throws CloudException {
String username = ConfigurationManager.getInstance().readString(USERNAME_KEY, null);
String token = ConfigurationManager.getInstance().readString(TOKEN_KEY, null);
@@ -282,14 +304,15 @@ public class CloudPresenter {
LOG.info("Received " + projects.size() + " results. Downloading thumbnails...");
// Download thumbnails and replace urls with local paths to speed up loading in the main
// thread
- for (int i = 0; i < projects.size(); i++) {
- String url = projects.get(i).getThumbnailUrl();
+ for (ProjectEntity project : projects) {
+ String url = project.getThumbnailUrl();
URL website = new URL(url);
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
File temp = File.createTempFile("thumbnail", ".png");
FileOutputStream fos = new FileOutputStream(temp);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
- projects.get(i).setThumbnailUrl(temp.getAbsolutePath());
+ project.setThumbnailUrl(temp.getAbsolutePath());
+ project.setCategories(getCategories());
fos.close();
}
LOG.info("Finished downloading thumbnails.");
@@ -324,6 +347,20 @@ public class CloudPresenter {
}
}
+ public List getProjectProperties(ProjectEntity project) {
+ List properties = ComponentProcessor.getInstance().extractProperties(ProjectEntity.class);
+ try {
+ for (PropertyWrapper property : properties) {
+ property.readFrom(project);
+ }
+ } catch (Exception e) {
+ LOG.error("Could not get project entity properties", e);
+ return null;
+ }
+ Collections.sort(properties, ComparatorFactory.getInstance().getDefaultPropertyComparator());
+ return properties;
+ }
+
private String getMachineId() {
if (machineId == null) {
try {
diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java b/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java
index ef9d689a..1c405df3 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/ComparatorFactory.java
@@ -67,6 +67,27 @@ public class ComparatorFactory {
return propertyNameComparator;
}
+ /**
+ * Creates a comparator that compares properties by sort order and then by name
+ * @return
+ */
+ public Comparator getDefaultPropertyComparator() {
+ if (propertyNameComparator == null) {
+ propertyNameComparator = new Comparator() {
+
+ @Override
+ public int compare(PropertyWrapper o1, PropertyWrapper o2) {
+ int comp = new Integer(o1.getSortOrder()).compareTo(o2.getSortOrder());
+ if (comp != 0)
+ return comp;
+ return o1.getName().compareToIgnoreCase(o2.getName());
+ }
+
+ };
+ }
+ return propertyNameComparator;
+ }
+
public Comparator> getComponentZOrderComparator() {
if (componentZOrderComparator == null) {
componentZOrderComparator = new Comparator>() {
diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
index 68529469..768b88e2 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
@@ -154,7 +154,7 @@ public class ComponentProcessor {
Method setter = clazz.getMethod("set" + method.getName().substring(3), method.getReturnType());
PropertyWrapper property =
new PropertyWrapper(name, method.getReturnType(), method.getName(), setter.getName(),
- annotation.defaultable(), validator);
+ annotation.defaultable(), validator, annotation.additionalOptions(), annotation.sortOrder());
properties.add(property);
}
} catch (NoSuchMethodException e) {
@@ -228,7 +228,7 @@ public class ComponentProcessor {
// }
// }
}
- Collections.sort(properties, ComparatorFactory.getInstance().getPropertyNameComparator());
+ Collections.sort(properties, ComparatorFactory.getInstance().getDefaultPropertyComparator());
return properties;
}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
index 303b4ce8..179307a0 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
@@ -1691,7 +1691,7 @@ public class Presenter implements IPlugInPort {
LOG.error("Could not get project properties", e);
return null;
}
- Collections.sort(properties, ComparatorFactory.getInstance().getPropertyNameComparator());
+ Collections.sort(properties, ComparatorFactory.getInstance().getDefaultPropertyComparator());
return properties;
}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java b/diylc/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java
index a8414f80..a6ca7798 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java
@@ -58,7 +58,11 @@ public class DialogFactory {
}
public PropertyEditorDialog createPropertyEditorDialog(List properties, String title) {
- PropertyEditorDialog editor = new PropertyEditorDialog(mainFrame, properties, title);
+ return createPropertyEditorDialog(mainFrame, properties, title);
+ }
+
+ public PropertyEditorDialog createPropertyEditorDialog(JFrame owner, List properties, String title) {
+ PropertyEditorDialog editor = new PropertyEditorDialog(owner, properties, title);
return editor;
}
@@ -147,7 +151,8 @@ public class DialogFactory {
return dialog;
}
- public UploadDialog createUploadDialog(JFrame ownerFrame, IPlugInPort plugInPort, String[] categories, boolean isUpdate) {
+ public UploadDialog createUploadDialog(JFrame ownerFrame, IPlugInPort plugInPort, String[] categories,
+ boolean isUpdate) {
UploadDialog dialog = new UploadDialog(ownerFrame, plugInPort, categories, isUpdate);
return dialog;
}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/components/HTMLTextArea.java b/diylc/diylc-swing/src/org/diylc/swing/gui/components/HTMLTextArea.java
new file mode 100644
index 00000000..c326c2db
--- /dev/null
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/components/HTMLTextArea.java
@@ -0,0 +1,31 @@
+package org.diylc.swing.gui.components;
+
+import javax.swing.JTextArea;
+
+/**
+ * {@link JTextArea} that replaces new line characters with html <br> tags.
+ *
+ * @author Branislav Stojkovic
+ */
+public class HTMLTextArea extends JTextArea {
+
+ private static final long serialVersionUID = 1L;
+
+ public HTMLTextArea(String text) {
+ super(text.replace("
", "\n"));
+ }
+
+ public HTMLTextArea() {
+ super();
+ }
+
+ @Override
+ public String getText() {
+ return super.getText().replace("\n", "
");
+ }
+
+ @Override
+ public void setText(String t) {
+ super.setText(t.replace("
", "\n"));
+ }
+}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java
index a1464e93..cdebbe1c 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java
@@ -9,6 +9,7 @@ import javax.swing.JLabel;
import org.apache.log4j.Logger;
import org.diylc.common.PropertyWrapper;
+import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.AbstractMeasure;
public class FieldEditorFactory {
@@ -16,6 +17,14 @@ public class FieldEditorFactory {
private static final Logger LOG = Logger.getLogger(FieldEditorFactory.class);
public static Component createFieldEditor(PropertyWrapper property) {
+ if (property.getType().equals(String.class) && property.getListItems() != null) {
+ StringListEditor editor = new StringListEditor(property);
+ return editor;
+ }
+ if (property.getType().equals(String.class) && EditableProperty.MULTI_LINE.equals(property.getAdditionalOptions())) {
+ MultiLineStringEditor editor = new MultiLineStringEditor(property);
+ return editor;
+ }
if (property.getType().equals(String.class)) {
StringEditor editor = new StringEditor(property);
return editor;
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java
new file mode 100644
index 00000000..b879d004
--- /dev/null
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/MultiLineStringEditor.java
@@ -0,0 +1,66 @@
+package org.diylc.swing.gui.editor;
+
+import java.awt.Color;
+import java.awt.Dimension;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import org.diylc.common.PropertyWrapper;
+import org.diylc.swing.gui.components.HTMLTextArea;
+import org.diylc.utils.Constants;
+
+public class MultiLineStringEditor extends JScrollPane {
+
+ private static final long serialVersionUID = 1L;
+
+ private Color oldBg;
+
+ private JTextArea textArea;
+
+ private final PropertyWrapper property;
+
+ public MultiLineStringEditor(PropertyWrapper property) {
+ super();
+ this.property = property;
+ setViewportView(getTextArea());
+ setPreferredSize(new Dimension(192, 64));
+ }
+
+ public JTextArea getTextArea() {
+ if (textArea == null) {
+ textArea = new HTMLTextArea(property.getValue() == null ? "" : (String) property.getValue());
+ textArea.setFont(getFont());
+ oldBg = textArea.getBackground();
+ textArea.getDocument().addDocumentListener(new DocumentListener() {
+
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ textChanged();
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ textChanged();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ textChanged();
+ }
+ });
+ if (!property.isUnique()) {
+ textArea.setBackground(Constants.MULTI_VALUE_COLOR);
+ }
+ }
+ return textArea;
+ }
+
+ private void textChanged() {
+ property.setChanged(true);
+ getTextArea().setBackground(oldBg);
+ property.setValue(getTextArea().getText());
+ }
+}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java
index 5b556288..046c0049 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java
@@ -92,19 +92,20 @@ public class PropertyEditorDialog extends ButtonDialog {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
- gbc.insets = new Insets(2, 2, 2, 2);
- gbc.anchor = GridBagConstraints.LINE_START;
+
+ gbc.anchor = GridBagConstraints.FIRST_LINE_START;
for (PropertyWrapper property : properties) {
gbc.gridx = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 0;
-
+ gbc.insets = new Insets(4, 2, 2, 2);
editorPanel.add(new JLabel(property.getName() + ": "), gbc);
gbc.gridx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
+ gbc.insets = new Insets(2, 2, 2, 2);
Component editor = FieldEditorFactory.createFieldEditor(property);
editor.addKeyListener(new KeyAdapter() {
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java
index e43cbfa6..ad03c7ed 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java
@@ -20,6 +20,7 @@ public class StringEditor extends JTextField {
public StringEditor(PropertyWrapper property) {
super(property.getValue() == null ? "" : (String) property.getValue());
this.property = property;
+ this.setColumns(32);
getDocument().addDocumentListener(new DocumentListener() {
@Override
diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java
new file mode 100644
index 00000000..bf618895
--- /dev/null
+++ b/diylc/diylc-swing/src/org/diylc/swing/gui/editor/StringListEditor.java
@@ -0,0 +1,41 @@
+package org.diylc.swing.gui.editor;
+
+import java.awt.Color;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+
+import org.diylc.common.PropertyWrapper;
+import org.diylc.utils.Constants;
+
+public class StringListEditor extends JComboBox {
+
+ private static final long serialVersionUID = 1L;
+
+ private Color oldBg = getBackground();
+
+ private final PropertyWrapper property;
+
+ public StringListEditor(final PropertyWrapper property) {
+ this.property = property;
+ Object[] values = property.getListItems();
+ setModel(new DefaultComboBoxModel(values));
+ setSelectedItem(property.getValue());
+ addItemListener(new ItemListener() {
+
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ property.setChanged(true);
+ setBackground(oldBg);
+ StringListEditor.this.property.setValue(e.getItem());
+ }
+ }
+ });
+ if (!property.isUnique()) {
+ setBackground(Constants.MULTI_VALUE_COLOR);
+ }
+ }
+}
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java
index f158fe2d..844c1728 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java
@@ -24,6 +24,7 @@ import org.diylc.plugins.cloud.model.CommentEntity;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISimpleView;
+import org.diylc.swing.gui.components.HTMLTextArea;
public class CommentDialog extends JDialog {
@@ -119,7 +120,7 @@ public class CommentDialog extends JDialog {
private JTextArea getReplyArea() {
if (replyArea == null) {
- replyArea = new JTextArea();
+ replyArea = new HTMLTextArea();
replyArea.setFont(getSendButton().getFont());
}
return replyArea;
@@ -132,7 +133,7 @@ public class CommentDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
- final String comment = getReplyArea().getText().replace("\n", "
");
+ final String comment = getReplyArea().getText();
if (comment.trim().length() == 0)
owner.showMessage("Cannot post an empty comment.", "Cloud Error", IView.ERROR_MESSAGE);
@@ -179,7 +180,7 @@ public class CommentDialog extends JDialog {
+ c.getPostedAt() + "