Dépôt officiel du code source de l'ERP OpenConcerto
/trunk/OpenConcerto/.classpath |
---|
38,5 → 38,7 |
<classpathentry kind="lib" path="lib/json-smart-1.3.1.jar"/> |
<classpathentry kind="lib" path="lib/icu4j-56_1-module_format+calendar.jar"/> |
<classpathentry kind="lib" path="lib/icu4j-56-data-western_europe.jar"/> |
<classpathentry kind="lib" path="lib/DS_Desktop_Notify.jar"/> |
<classpathentry kind="lib" path="lib/mime_util.jar"/> |
<classpathentry kind="output" path="bin"/> |
</classpath> |
/trunk/OpenConcerto/lib/icudata_56.jar |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/trunk/OpenConcerto/lib/icudata_56.jar |
---|
Nouveau fichier |
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/lib/mime_util.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/mime_util.jar |
=================================================================== |
--- trunk/OpenConcerto/lib/mime_util.jar (revision 0) |
+++ trunk/OpenConcerto/lib/mime_util.jar (revision 142) |
/trunk/OpenConcerto/lib/mime_util.jar |
---|
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/lib/jOpenCalendar.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/mysql-connector-java-5.1.40-bin.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/mysql-connector-java-5.1.40-bin.jar |
=================================================================== |
--- trunk/OpenConcerto/lib/mysql-connector-java-5.1.40-bin.jar (revision 0) |
+++ trunk/OpenConcerto/lib/mysql-connector-java-5.1.40-bin.jar (revision 142) |
/trunk/OpenConcerto/lib/mysql-connector-java-5.1.40-bin.jar |
---|
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/lib/accessors-smart-1.1.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/accessors-smart-1.1.jar |
=================================================================== |
--- trunk/OpenConcerto/lib/accessors-smart-1.1.jar (revision 0) |
+++ trunk/OpenConcerto/lib/accessors-smart-1.1.jar (revision 142) |
/trunk/OpenConcerto/lib/accessors-smart-1.1.jar |
---|
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/lib/jOpenDocument-1.4rc2.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/DS_Desktop_Notify.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/DS_Desktop_Notify.jar |
=================================================================== |
--- trunk/OpenConcerto/lib/DS_Desktop_Notify.jar (revision 0) |
+++ trunk/OpenConcerto/lib/DS_Desktop_Notify.jar (revision 142) |
/trunk/OpenConcerto/lib/DS_Desktop_Notify.jar |
---|
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/lib/json-smart-2.2.1.jar |
=================================================================== |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Index: trunk/OpenConcerto/lib/json-smart-2.2.1.jar |
=================================================================== |
--- trunk/OpenConcerto/lib/json-smart-2.2.1.jar (revision 0) |
+++ trunk/OpenConcerto/lib/json-smart-2.2.1.jar (revision 142) |
/trunk/OpenConcerto/lib/json-smart-2.2.1.jar |
---|
Changements de propriété: |
Added: svn:mime-type |
## -0,0 +1 ## |
+application/octet-stream |
\ No newline at end of property |
Index: trunk/OpenConcerto/src/interpreterDJava/JavaEditor.java |
=================================================================== |
--- trunk/OpenConcerto/src/interpreterDJava/JavaEditor.java (revision 141) |
+++ trunk/OpenConcerto/src/interpreterDJava/JavaEditor.java (revision 142) |
@@ -12,6 +12,7 @@ |
import java.io.FileReader; |
import java.io.FileWriter; |
import java.io.IOException; |
+import java.io.Writer; |
import java.math.BigDecimal; |
import java.util.HashMap; |
import java.util.Map; |
@@ -24,15 +25,15 @@ |
import javax.swing.Scrollable; |
import javax.swing.SwingConstants; |
+import org.jedit.JEditTextArea; |
+import org.jedit.JavaTokenMarker; |
+import org.jedit.Token; |
+ |
import koala.dynamicjava.interpreter.Interpreter; |
import koala.dynamicjava.interpreter.InterpreterException; |
import koala.dynamicjava.interpreter.TreeInterpreter; |
import koala.dynamicjava.parser.wrapper.JavaCCParserFactory; |
-import org.jedit.JEditTextArea; |
-import org.jedit.JavaTokenMarker; |
-import org.jedit.Token; |
- |
// FIXME afficher les infos sur les variables via uen popup |
public class JavaEditor extends JPanel implements Scrollable { |
@@ -208,7 +209,7 @@ |
* @param varName |
* @param value |
*/ |
- protected void defineVariable(final Interpreter interpret, final BufferedWriter b, final String varName, final Object value) { |
+ protected void defineVariable(final Interpreter interpret, final Writer b, final String varName, final Object value) { |
if (value == null) { |
try { |
/trunk/OpenConcerto/src/product.properties |
---|
1,2 → 1,5 |
NAME=OpenConcerto |
VERSION=1.4.2 |
VERSION=1.5 |
ORGANIZATION_NAME=OpenConcerto |
ORGANIZATION_ID=org.openconcerto |
/trunk/OpenConcerto/src/org/jopendocument/link/OOConnexion.java |
---|
117,15 → 117,33 |
} |
public static void main(String[] args) throws IOException { |
if (args.length == 0) { |
System.out.println("Usage : " + OOConnexion.class.getName() + " officeFile"); |
if (args.length == 0 || args.length > 2) { |
System.out.println("Usage : " + OOConnexion.class.getName() + " officeFile | --type param"); |
System.out.println("Open officeFile in the default installation of LibreOffice"); |
System.out.println("--type is either file or url"); |
System.exit(1); |
} |
final OOConnexion conn = OOConnexion.create(); |
if (conn == null) |
throw new IllegalStateException("No Office found"); |
conn.loadDocument(new File(args[0]), false); |
final boolean file; |
final String arg; |
if (args.length == 1) { |
file = true; |
arg = args[0]; |
} else if (args[0].equals("--file")) { |
file = true; |
arg = args[1]; |
} else if (args[0].equals("--url")) { |
file = false; |
arg = args[1]; |
} else { |
throw new IllegalArgumentException("Type not valid : " + args[0]); |
} |
if (file) |
conn.loadDocument(new File(arg), false); |
else |
conn.loadDocumentFromURLAsync(arg, false); |
conn.closeConnexion(); |
} |
/trunk/OpenConcerto/src/org/jopenchart/sample/devguide/PieChartSample.java |
---|
63,14 → 63,13 |
private static void chart3() { |
PieChartWithSeparatedLabels c = new PieChartWithSeparatedLabels(); |
c.setInnerDimension(50, 50); |
c.addLabel(new Label("AAAAAA"), Color.red); |
c.addLabel(new Label("BBBB")); |
c.addLabel(new Label("CCCCCCCCCCCCCCCCCCCCCCCCCCCC")); |
c.addLabel(new Label("D")); |
c.addLabel(new Label("EEE")); |
c.addLabel(new Label("FFF")); |
c.addLabel(new Label("GG")); |
c.addLabel(new Label("HHH")); |
c.setDimension(new Dimension(400, 200)); |
ArrayList<Number> l = new ArrayList<Number>(); |
/trunk/OpenConcerto/src/org/openconcerto/map/model/Ville.java |
---|
230,7 → 230,7 |
} |
public static synchronized Ville getVilleContaining(String string, String codepostal) { |
if (codepostal.length() < 0 && string.length() <= 2) { |
if (codepostal.length() == 0 && string.length() <= 2) { |
return null; |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableComboCompletionThread.java |
---|
87,6 → 87,9 |
final String aText = this.t.trim(); |
final String normalizedText = aText.length() < minimumSearch ? "" : aText; |
// null : not searchable |
// true : search changed |
// false : search didn't change |
Boolean searched = null; |
// If there was a search and now the text is below minimum, we must unset the search |
// Efficient since setSearch() only carry out its action if the search changes |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableCombo.java |
---|
16,6 → 16,7 |
import static org.openconcerto.ui.component.ComboLockedMode.ITEMS_LOCKED; |
import static org.openconcerto.ui.component.ComboLockedMode.LOCKED; |
import static org.openconcerto.ui.component.ComboLockedMode.UNLOCKED; |
import org.openconcerto.laf.LAFUtils; |
import org.openconcerto.ui.TM; |
import org.openconcerto.ui.component.ComboLockedMode; |
25,19 → 26,21 |
import org.openconcerto.ui.component.MutableListCombo; |
import org.openconcerto.ui.component.MutableListComboPopupListener; |
import org.openconcerto.ui.component.text.DocumentComponent; |
import org.openconcerto.ui.component.text.TextBehaviour; |
import org.openconcerto.ui.component.text.TextComponent; |
import org.openconcerto.ui.valuewrapper.ValueChangeSupport; |
import org.openconcerto.ui.valuewrapper.ValueWrapper; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.ListMap; |
import org.openconcerto.utils.Value; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.cc.IdentityHashSet; |
import org.openconcerto.utils.checks.ValidListener; |
import org.openconcerto.utils.checks.ValidState; |
import org.openconcerto.utils.model.DefaultIMutableListModel; |
import org.openconcerto.utils.model.IListModel; |
import org.openconcerto.utils.model.IMutableListModel; |
import org.openconcerto.utils.model.ISearchable; |
import org.openconcerto.utils.model.ListComboBoxModel; |
import org.openconcerto.utils.model.NewSelection; |
import org.openconcerto.utils.model.Reloadable; |
56,6 → 59,7 |
import java.awt.Point; |
import java.awt.Rectangle; |
import java.awt.color.ColorSpace; |
import java.awt.event.ActionEvent; |
import java.awt.event.ComponentAdapter; |
import java.awt.event.ComponentEvent; |
import java.awt.event.FocusAdapter; |
72,11 → 76,9 |
import java.beans.PropertyChangeListener; |
import java.util.ArrayList; |
import java.util.Collection; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.List; |
import java.util.Map; |
import javax.swing.AbstractAction; |
import javax.swing.Action; |
import javax.swing.Icon; |
import javax.swing.ImageIcon; |
127,6 → 129,7 |
protected final ISearchableComboPopup<T> popupCompletion; |
// fullList |
private final DefaultIMutableListModel<ISearchableComboItem<T>> model; |
protected ISearchableComboItem<T> initialValue; |
// list for the popup |
private final ListComboBoxModel listModel; |
private final ISearchableComboItem<T> emptyItem; |
160,7 → 163,7 |
private int minimumSearch = 1; |
private int maximumResult = 300; |
private final Map<T, ISearchableComboItem<T>> itemsByOriginalItem; |
private final ListMap<T, ISearchableComboItem<T>> itemsByOriginalItem; |
protected boolean updating = false; |
private ValidState parsedValidState = ValidState.getTrueInstance(); |
private ValidState validState = ValidState.createCached(false, "Not initialised"); |
205,7 → 208,7 |
// items |
this.actions = new ArrayList<Action>(); |
this.cache = null; |
this.itemsByOriginalItem = new HashMap<T, ISearchableComboItem<T>>(); |
this.itemsByOriginalItem = new ListMap<T, ISearchableComboItem<T>>(); |
this.model = new DefaultIMutableListModel<ISearchableComboItem<T>>(); |
this.getModel().setSelectOnAdd(false); |
this.setOnRemovingOrReplacingSelection(NewSelection.NONE); |
610,12 → 613,10 |
for (final T originalItem : originalItems) { |
final ISearchableComboItem<T> textSelectorItem; |
if (this.itemsByOriginalItem.containsKey(originalItem)) { |
// allow another item with the same original : add another item to our model, but |
// keep the first one in itemsByOriginalItem (this map is only used in setValue() to |
// quickly find the ISearchableComboItem) |
// allow another item with the same original since our source is a list |
textSelectorItem = createItem(originalItem); |
// see ISearchableComboPopup.validateSelection() |
assert !textSelectorItem.equals(this.itemsByOriginalItem.get(originalItem)) : "Have to not be equal to be able to choose one or the other"; |
assert !this.itemsByOriginalItem.get(originalItem).contains(textSelectorItem) : "Have to not be equal to be able to choose one or the other"; |
} else { |
// reuse the selected value, otherwise the popup will select nothing |
if (sel != null && CompareUtils.equals(selOriginal, originalItem)) |
622,19 → 623,25 |
textSelectorItem = sel; |
else |
textSelectorItem = createItem(originalItem); |
this.itemsByOriginalItem.put(originalItem, textSelectorItem); |
} |
this.itemsByOriginalItem.add(originalItem, textSelectorItem); |
toAdd.add(textSelectorItem); |
} |
// only 1 fire |
this.getModel().addAll(index, toAdd); |
assert this.itemsByOriginalItem.allValues().size() == getModel().getSize(); |
} |
private void rmItemsFromModel(final int index0, final int index1) { |
if (index0 == 0 && index1 == getModel().getSize() - 1) { |
this.itemsByOriginalItem.clear(); |
} else { |
for (final ISearchableComboItem<T> item : getModel().getList().subList(index0, index1 + 1)) { |
this.itemsByOriginalItem.remove(item.getOriginal(), item); |
} |
} |
getModel().removeElementsAt(index0, index1); |
// remove from our map |
// ATTN for ~35000 items, new HashSet() got us from 6000ms to 8ms ! |
this.itemsByOriginalItem.keySet().retainAll(new HashSet<T>(getCache().getList())); |
assert this.itemsByOriginalItem.allValues().size() == getModel().getSize(); |
} |
// conversion |
744,11 → 751,12 |
final ISearchableComboItem<T> comboItem; |
// as in docChanged(), "" means empty (otherwise an ISearchableComboItem will be created and |
// it won't be contained in the list) |
if (val == null || "".equals(val)) |
if (val == null || "".equals(val) || !valid.isValid()) { |
comboItem = null; |
else if (this.itemsByOriginalItem.containsKey(val)) { |
comboItem = this.itemsByOriginalItem.get(val); |
} else if (this.itemsByOriginalItem.containsKey(val)) { |
comboItem = this.itemsByOriginalItem.get(val).get(0); |
} else { |
log("in " + this.getClass().getSimpleName() + ".setValue createItem() since not found"); |
// always set the passed value, even if it's not valid (e.g. |
// getMode().valueMustBeInList()) |
comboItem = createItem(val); |
758,8 → 766,7 |
final void setValue(final ISearchableComboItem<T> val) { |
log("entering " + this.getClass().getSimpleName() + ".setValue(ISearchableComboItem) " + val); |
assert this.isEmptyItem(val) || new IdentityHashSet<ISearchableComboItem<T>>(this.getModelValues()).contains(val) : "Item not in model, perhaps use setValue(T)"; |
// valid since val is in our model |
// valid since we didn't try to parse a string |
this.setComboItemValue(val, ValidState.getTrueInstance()); |
} |
801,6 → 808,22 |
this.updateValidState(); |
this.supp.fireValueChange(); |
// the selection has changed, this is where we reset the search |
// some caches force the inclusion of the selection, so clear the search after setting the |
// value to avoid : |
// 1. clear search |
// 2. cache reloads without the selection |
// 3. fireValueChange() |
// 4. cache reloads again to include the selection |
// instead we want : |
// 1. fireValueChange() |
// 2. no reload since in general the value was in the cache |
// 3. clear search |
// 4. cache reloads with the selection |
if (this.getCache() instanceof ISearchable) { |
((ISearchable) this.getCache()).setSearch(null, null); |
} |
} |
private final void setText(final String newText) { |
832,9 → 855,11 |
protected final void docChanged(final DocumentEvent e) { |
if (!this.updating) { |
final String text = SimpleDocumentListener.getText(e.getDocument()); |
final T val; |
ValidState valid = ValidState.getTrueInstance(); |
if (text.length() == 0) { |
// "" means empty |
this.setValue(null, ValidState.getTrueInstance()); |
val = null; |
} else if (this.getMode().valueMustBeInList() && !this.getMode().isListMutable()) { |
// value can only be set by the popup (or setMatchingCompletions()) ; the list |
// cannot be modified. Thus don't call stringToT() as it might not be implemented |
842,14 → 867,18 |
// this avoids having to decide between 2 different values with the same label, or |
// worse this is locked and one of those 2 values are not in us. In that case |
// setting the invalid one will in fact select the other. |
this.setValue(null, ValidState.createCached(false, "la valeur n'a pas été sélectionnée dans la liste")); |
val = null; |
valid = ValidState.createCached(false, "la valeur n'a pas été sélectionnée dans la liste"); |
} else { |
T parsed = null; |
try { |
this.setValue(stringToT(text)); |
parsed = stringToT(text); |
} catch (Exception exn) { |
this.setValue(null, ValidState.createCached(false, "la valeur n'est pas correcte: " + exn.getLocalizedMessage())); |
valid = ValidState.createCached(false, "la valeur n'est pas correcte: " + exn.getLocalizedMessage()); |
} |
val = valid.isValid() ? parsed : null; |
} |
this.setValue(val, valid); |
if (this.isSearchable()) |
this.updateAutoCompletion(text); |
} |
1202,6 → 1231,8 |
@Override |
public void focusGained(FocusEvent e) { |
firePropertyChange("textCompFocused", false, true); |
// set on focus gained like TextBehaviour |
ISearchableCombo.this.initialValue = getSelection(); |
} |
@Override |
1211,6 → 1242,20 |
firePropertyChange("textCompFocused", true, false); |
} |
}); |
this.text.getActionMap().put(TextBehaviour.REVERT_ACTION_KEY, new AbstractAction() { |
@Override |
public void actionPerformed(ActionEvent e) { |
final ISearchableComboItem<T> v = ISearchableCombo.this.initialValue; |
if (v == null || getModel().getList().contains(v)) { |
// quicker and allow to tell apart original items that are equal |
setValue(v); |
} else { |
// the combo might have been refreshed several times and the initial item gone. |
// But there might be a new one with the same value. |
setValue(v.getOriginal()); |
} |
} |
}); |
this.text.addMouseListener(this.clickL); |
this.text.addMouseMotionListener(this.dragL); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/text/TextBehaviour.java |
---|
13,22 → 13,34 |
package org.openconcerto.ui.component.text; |
import java.awt.event.ActionEvent; |
import java.awt.event.FocusAdapter; |
import java.awt.event.FocusEvent; |
import java.awt.event.KeyAdapter; |
import java.awt.event.FocusListener; |
import java.awt.event.KeyEvent; |
import java.awt.event.MouseAdapter; |
import java.awt.event.MouseEvent; |
import javax.swing.AbstractAction; |
import javax.swing.JComponent; |
import javax.swing.KeyStroke; |
import javax.swing.text.JTextComponent; |
/** |
* Listens to its passed text component to select all on focus gained and revert when pressing ESC. |
* To control the revert action use {@link #REVERT_ACTION_KEY}. |
* |
* @author Sylvain |
*/ |
public class TextBehaviour { |
/** |
* Use this key to register the revert action in {@link JComponent#getActionMap()}. If none is |
* set, this class will simply set an action that {@link JTextComponent#setText(String) restore} |
* the text that was on {@link FocusListener#focusGained(FocusEvent) focus gained}. |
*/ |
public static final String REVERT_ACTION_KEY = "action map key to revert value"; |
// MAYBE faire un stopManage() qui enlèverait tous les listeners |
public static final TextBehaviour manage(JTextComponent comp) { |
return new TextBehaviour(comp); |
48,6 → 60,7 |
// select all on focus gained |
// except if the user is selecting with the mouse |
this.comp.addFocusListener(new FocusAdapter() { |
@Override |
public void focusGained(FocusEvent e) { |
TextBehaviour.this.gained = true; |
TextBehaviour.this.initialText = TextBehaviour.this.comp.getText(); |
57,10 → 70,12 |
} |
}); |
this.comp.addMouseListener(new MouseAdapter() { |
@Override |
public void mousePressed(MouseEvent e) { |
TextBehaviour.this.mousePressed = true; |
} |
@Override |
public void mouseReleased(MouseEvent e) { |
// don't override the user selection |
if (TextBehaviour.this.gained && TextBehaviour.this.comp.getSelectedText() == null) { |
71,15 → 86,16 |
TextBehaviour.this.mousePressed = false; |
} |
}); |
this.comp.addKeyListener(new KeyAdapter() { |
public void keyTyped(KeyEvent keyEvent) { |
// Sert a annuler une saisie |
if (keyEvent.getKeyChar() == KeyEvent.VK_ESCAPE) { |
this.comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), REVERT_ACTION_KEY); |
if (this.comp.getActionMap().get(REVERT_ACTION_KEY) == null) { |
this.comp.getActionMap().put(REVERT_ACTION_KEY, new AbstractAction() { |
@Override |
public void actionPerformed(ActionEvent e) { |
TextBehaviour.this.comp.setText(TextBehaviour.this.initialText); |
TextBehaviour.this.comp.selectAll(); |
} |
} |
}); |
}); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/DialogCallbackHandler.java |
---|
Nouveau fichier |
0,0 → 1,307 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.component; |
/* Java imports */ |
import java.awt.Component; |
import java.awt.event.HierarchyEvent; |
import java.awt.event.HierarchyListener; |
import java.util.ArrayList; |
import java.util.Iterator; |
import java.util.List; |
import java.util.concurrent.Callable; |
import java.util.concurrent.FutureTask; |
import java.util.concurrent.RunnableFuture; |
/* JAAS imports */ |
import javax.security.auth.callback.Callback; |
import javax.security.auth.callback.CallbackHandler; |
import javax.security.auth.callback.ConfirmationCallback; |
import javax.security.auth.callback.NameCallback; |
import javax.security.auth.callback.PasswordCallback; |
import javax.security.auth.callback.TextOutputCallback; |
import javax.security.auth.callback.UnsupportedCallbackException; |
import javax.swing.Box; |
import javax.swing.JLabel; |
import javax.swing.JOptionPane; |
import javax.swing.JPasswordField; |
import javax.swing.JTextField; |
import javax.swing.SwingUtilities; |
import javax.swing.text.JTextComponent; |
/** |
* <p> |
* Uses a Swing dialog window to query the user for answers to authentication questions. This can be |
* used by a JAAS application to instantiate a CallbackHandler |
* |
* @see javax.security.auth.callback |
*/ |
public class DialogCallbackHandler implements CallbackHandler { |
/* -- Fields -- */ |
/* The parent window, or null if using the default parent */ |
private final Component parentComponent; |
private static final int JPasswordFieldLen = 8; |
private static final int JTextFieldLen = 8; |
/* -- Methods -- */ |
/** |
* Creates a callback dialog with the default parent window. |
*/ |
public DialogCallbackHandler() { |
this(null); |
} |
/** |
* Creates a callback dialog and specify the parent window. |
* |
* @param parentComponent the parent window -- specify <code>null</code> for the default parent |
*/ |
public DialogCallbackHandler(final Component parentComponent) { |
this.parentComponent = parentComponent; |
} |
/* |
* An interface for recording actions to carry out if the user clicks OK for the dialog. |
*/ |
private static interface Action { |
void perform(); |
} |
/** |
* Handles the specified set of callbacks. |
* |
* @param callbacks the callbacks to handle |
* @throws UnsupportedCallbackException if the callback is not an instance of NameCallback or |
* PasswordCallback |
*/ |
@Override |
public void handle(final Callback[] callbacks) throws UnsupportedCallbackException { |
/* Collect messages to display in the dialog */ |
final List<Object> messages = new ArrayList<Object>(3); |
/* Collection actions to perform if the user clicks OK */ |
final List<Action> okActions = new ArrayList<Action>(2); |
final ConfirmationInfo confirmation = new ConfirmationInfo(); |
final List<JTextComponent> fields = new ArrayList<JTextComponent>(); |
for (int i = 0; i < callbacks.length; i++) { |
if (callbacks[i] instanceof TextOutputCallback) { |
final TextOutputCallback tc = (TextOutputCallback) callbacks[i]; |
switch (tc.getMessageType()) { |
case TextOutputCallback.INFORMATION: |
confirmation.messageType = JOptionPane.INFORMATION_MESSAGE; |
break; |
case TextOutputCallback.WARNING: |
confirmation.messageType = JOptionPane.WARNING_MESSAGE; |
break; |
case TextOutputCallback.ERROR: |
confirmation.messageType = JOptionPane.ERROR_MESSAGE; |
break; |
default: |
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized message type"); |
} |
messages.add(tc.getMessage()); |
} else if (callbacks[i] instanceof NameCallback) { |
final NameCallback nc = (NameCallback) callbacks[i]; |
final JLabel prompt = new JLabel(nc.getPrompt()); |
final JTextField name = new JTextField(JTextFieldLen); |
final String defaultName = nc.getDefaultName(); |
if (defaultName != null) { |
name.setText(defaultName); |
} |
/* |
* Put the prompt and name in a horizontal box, and add that to the set of messages. |
*/ |
final Box namePanel = Box.createHorizontalBox(); |
namePanel.add(prompt); |
namePanel.add(name); |
messages.add(namePanel); |
/* Store the name back into the callback if OK */ |
okActions.add(new Action() { |
@Override |
public void perform() { |
nc.setName(name.getText()); |
} |
}); |
fields.add(name); |
} else if (callbacks[i] instanceof PasswordCallback) { |
final PasswordCallback pc = (PasswordCallback) callbacks[i]; |
final JLabel prompt = new JLabel(pc.getPrompt()); |
final JPasswordField password = new JPasswordField(JPasswordFieldLen); |
if (!pc.isEchoOn()) { |
password.setEchoChar('*'); |
} |
final Box passwordPanel = Box.createHorizontalBox(); |
passwordPanel.add(prompt); |
passwordPanel.add(password); |
messages.add(passwordPanel); |
okActions.add(new Action() { |
@Override |
public void perform() { |
pc.setPassword(password.getPassword()); |
} |
}); |
fields.add(password); |
} else if (callbacks[i] instanceof ConfirmationCallback) { |
final ConfirmationCallback cc = (ConfirmationCallback) callbacks[i]; |
confirmation.setCallback(cc); |
if (cc.getPrompt() != null) { |
messages.add(cc.getPrompt()); |
} |
} else { |
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); |
} |
} |
// TODO also create dialog in the EDT |
final RunnableFuture<Integer> f = new FutureTask<Integer>(new Callable<Integer>() { |
@Override |
public Integer call() throws Exception { |
if (!fields.isEmpty()) { |
fields.get(0).addHierarchyListener(new HierarchyListener() { |
@Override |
public void hierarchyChanged(final HierarchyEvent e) { |
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && e.getComponent().isVisible()) { |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
e.getComponent().requestFocus(); |
} |
}); |
} |
} |
}); |
} |
/* Display the dialog */ |
return JOptionPane.showOptionDialog(DialogCallbackHandler.this.parentComponent, messages.toArray(), "Confirmation", /* title */ |
confirmation.optionType, confirmation.messageType, null, /* icon */ |
confirmation.options, /* options */ |
confirmation.initialValue); /* initialValue */ |
} |
}); |
SwingUtilities.invokeLater(f); |
final int result; |
try { |
result = f.get(); |
} catch (Exception e) { |
throw new IllegalStateException(e); |
} |
/* Perform the OK actions */ |
if (result == JOptionPane.OK_OPTION || result == JOptionPane.YES_OPTION) { |
final Iterator<Action> iterator = okActions.iterator(); |
while (iterator.hasNext()) { |
iterator.next().perform(); |
} |
} |
confirmation.handleResult(result); |
} |
/* |
* Provides assistance with translating between JAAS and Swing confirmation dialogs. |
*/ |
private static class ConfirmationInfo { |
private int[] translations; |
int optionType = JOptionPane.OK_CANCEL_OPTION; |
Object[] options = null; |
Object initialValue = null; |
int messageType = JOptionPane.QUESTION_MESSAGE; |
private ConfirmationCallback callback; |
/* Set the confirmation callback handler */ |
void setCallback(final ConfirmationCallback callback) throws UnsupportedCallbackException { |
this.callback = callback; |
final int confirmationOptionType = callback.getOptionType(); |
switch (confirmationOptionType) { |
case ConfirmationCallback.YES_NO_OPTION: |
this.optionType = JOptionPane.YES_NO_OPTION; |
this.translations = new int[] { JOptionPane.YES_OPTION, ConfirmationCallback.YES, JOptionPane.NO_OPTION, ConfirmationCallback.NO, JOptionPane.CLOSED_OPTION, ConfirmationCallback.NO }; |
break; |
case ConfirmationCallback.YES_NO_CANCEL_OPTION: |
this.optionType = JOptionPane.YES_NO_CANCEL_OPTION; |
this.translations = new int[] { JOptionPane.YES_OPTION, ConfirmationCallback.YES, JOptionPane.NO_OPTION, ConfirmationCallback.NO, JOptionPane.CANCEL_OPTION, |
ConfirmationCallback.CANCEL, JOptionPane.CLOSED_OPTION, ConfirmationCallback.CANCEL }; |
break; |
case ConfirmationCallback.OK_CANCEL_OPTION: |
this.optionType = JOptionPane.OK_CANCEL_OPTION; |
this.translations = new int[] { JOptionPane.OK_OPTION, ConfirmationCallback.OK, JOptionPane.CANCEL_OPTION, ConfirmationCallback.CANCEL, JOptionPane.CLOSED_OPTION, |
ConfirmationCallback.CANCEL }; |
break; |
case ConfirmationCallback.UNSPECIFIED_OPTION: |
this.options = callback.getOptions(); |
/* |
* There's no way to know if the default option means to cancel the login, but there |
* isn't a better way to guess this. |
*/ |
this.translations = new int[] { JOptionPane.CLOSED_OPTION, callback.getDefaultOption() }; |
break; |
default: |
throw new UnsupportedCallbackException(callback, "Unrecognized option type: " + confirmationOptionType); |
} |
final int confirmationMessageType = callback.getMessageType(); |
switch (confirmationMessageType) { |
case ConfirmationCallback.WARNING: |
this.messageType = JOptionPane.WARNING_MESSAGE; |
break; |
case ConfirmationCallback.ERROR: |
this.messageType = JOptionPane.ERROR_MESSAGE; |
break; |
case ConfirmationCallback.INFORMATION: |
this.messageType = JOptionPane.INFORMATION_MESSAGE; |
break; |
default: |
throw new UnsupportedCallbackException(callback, "Unrecognized message type: " + confirmationMessageType); |
} |
} |
/* Process the result returned by the Swing dialog */ |
void handleResult(int result) { |
if (this.callback == null) { |
return; |
} |
for (int i = 0; i < this.translations.length; i += 2) { |
if (this.translations[i] == result) { |
result = this.translations[i + 1]; |
break; |
} |
} |
this.callback.setSelectedIndex(result); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java |
---|
18,6 → 18,7 |
import static org.openconcerto.ui.component.ComboLockedMode.LOCKED; |
import static org.openconcerto.ui.component.ComboLockedMode.UNLOCKED; |
import org.openconcerto.ui.component.InteractionMode.InteractionComponent; |
import org.openconcerto.ui.component.combo.ISearchableComboPopup; |
import org.openconcerto.ui.component.text.TextComponent; |
492,11 → 493,19 |
* @return <code>true</code> if s is really added. |
*/ |
private final boolean addToCache(String s) { |
if (s != null && s.length() > 0 && this.getListModel().getList().indexOf(s) < 0) { |
this.addItem(makeObj(s)); |
return true; |
} else |
return false; |
final boolean added = s != null && s.length() > 0 && this.getListModel().getList().indexOf(s) < 0; |
if (added) { |
final Object obj = makeObj(s); |
// BasicComboBoxUI$Handler.intervalAdded(ListDataEvent) calls contentsChanged() which |
// calls JComboBox.configureEditor() with the current selection. But the selection is |
// only set by BasicComboBoxUI.Handler.focusLost() so this.addItem() replaces the |
// current editor value by the current selection. |
this.completing = true; |
this.setSelectedItem(obj); |
this.completing = false; |
this.addItem(obj); |
} |
return added; |
} |
private final void removeCurrentText() { |
/trunk/OpenConcerto/src/org/openconcerto/ui/component/HTMLTextField.java |
---|
13,9 → 13,14 |
package org.openconcerto.ui.component; |
import org.openconcerto.ui.TM; |
import org.openconcerto.utils.ExceptionHandler; |
import java.awt.Component; |
import java.awt.Desktop; |
import java.io.File; |
import java.net.URI; |
import java.net.URISyntaxException; |
import java.util.concurrent.ExecutorService; |
import java.util.concurrent.LinkedBlockingQueue; |
import java.util.concurrent.ThreadFactory; |
25,6 → 30,7 |
import javax.swing.BorderFactory; |
import javax.swing.JComponent; |
import javax.swing.JEditorPane; |
import javax.swing.JOptionPane; |
import javax.swing.JTextField; |
import javax.swing.event.HyperlinkEvent; |
import javax.swing.event.HyperlinkEvent.EventType; |
74,12 → 80,22 |
} |
protected void linkActivated(final HyperlinkEvent e, final JComponent src) { |
final URI uri = getURI(e); |
if (uri == null) |
return; |
if ("file".equals(uri.getScheme())) { |
final File f = new File(uri.getPath()); |
if (!f.exists()) { |
JOptionPane.showMessageDialog((Component) e.getSource(), TM.tr("missingFile", f), null, JOptionPane.WARNING_MESSAGE); |
return; |
} |
} |
// this ties into the OS and can block |
exec.submit(new Runnable() { |
@Override |
public void run() { |
try { |
Desktop.getDesktop().browse(e.getURL().toURI()); |
Desktop.getDesktop().browse(uri); |
} catch (Exception exn) { |
ExceptionHandler.handle(src, org.openconcerto.utils.i18n.TM.tr("linkOpenError", e.getURL()), exn); |
} |
86,4 → 102,13 |
} |
}); |
} |
private URI getURI(final HyperlinkEvent e) { |
try { |
return e.getURL().toURI(); |
} catch (URISyntaxException exn) { |
ExceptionHandler.handle((Component) e.getSource(), "Couldn't get URI", exn); |
return null; |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/NotSpecifedConvertor.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFilesWithSelectionContext.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/IUserControl.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/IUserControlContainer.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILabel.java |
---|
40,21 → 40,15 |
} |
public LightUILabel(final String id) { |
super(id); |
this.setType(TYPE_LABEL); |
this(id, "", false); |
} |
public LightUILabel(final String id, final boolean isBold) { |
super(id); |
this.setType(TYPE_LABEL); |
this.setFontBold(isBold); |
this(id, "", isBold); |
} |
public LightUILabel(final String id, final String label) { |
super(id); |
this.setType(TYPE_LABEL); |
this.setLabel(label); |
this(id, label, false); |
} |
public LightUILabel(final String id, final String label, final boolean isBold) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/StringValueConvertor.java |
---|
14,6 → 14,7 |
package org.openconcerto.ui.light; |
import java.util.List; |
import java.util.Map.Entry; |
public abstract class StringValueConvertor extends ComboValueConvertor<String> { |
30,9 → 31,11 |
/** |
* @param index: index of listId. |
* |
* @return id store at index in listId. |
* @return id store at index in listId or null if index is under 1. |
* |
* @throws IllegalArgumentException when index is out out bounds or if list of ids is not initialized |
*/ |
public String getIdFromIndex(final Integer index) { |
public String getIdFromIndex(final Integer index) throws IllegalArgumentException { |
int realIndex = index; |
// values start at 1. |
realIndex = index - 1; |
42,13 → 45,18 |
if (realIndex >= this.listId.size()) { |
throw new IllegalArgumentException("index is out of bounds"); |
} |
return this.listId.get(realIndex); |
if(realIndex == -1){ |
return null; |
} else { |
return this.listId.get(realIndex); |
} |
} |
/** |
* @param id: id store in listId. |
* |
* @return index of id in listId. |
* @return index of id in listId or null if not found. |
*/ |
public Integer getIndexFromId(final String id) { |
if (this.listId == null) { |
58,20 → 66,24 |
final int listIdSize = this.listId.size(); |
for (int i = 0; i < listIdSize; i++) { |
if (this.listId.get(i).equals(id)) { |
// values start at 1. |
// values start at 1. |
return i + 1; |
} |
} |
return null; |
} |
@Override |
public void fillComboWithValue(final LightUIComboBox combo) { |
public void fillComboWithValue(final LightUIComboBox combo, final String selectedValue) { |
int i = 1; |
for(final String value : this.values.values()) { |
for (final Entry<String, String> entry : this.values.entrySet()) { |
final LightUIComboBoxElement comboElement = new LightUIComboBoxElement(i); |
comboElement.setValue1(value); |
comboElement.setValue1(entry.getValue()); |
combo.addValue(comboElement); |
if (entry.getKey().equals(selectedValue)) { |
combo.setSelectedValue(comboElement); |
} |
i++; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITabbed.java |
---|
17,7 → 17,7 |
import net.minidev.json.JSONObject; |
public abstract class LightUITabbed extends LightUIContainer implements IUserControlContainer { |
public abstract class LightUITabbed extends LightUserControlContainer { |
// Init from json constructor |
public LightUITabbed(final JSONObject json) { |
super(json); |
50,15 → 50,19 |
} |
@Override |
public void setValueFromContext(final Object value) { |
public void _setValueFromContext(final Object value) { |
final JSONObject jsonContext = (JSONObject) JSONConverter.getObjectFromJSON(value, JSONObject.class); |
final int childCount = this.getChildrenCount(); |
for (int i = 0; i < childCount; i++) { |
final LightUITab child = this.getChild(i, LightUITab.class); |
if (jsonContext.containsKey(child.getUUID())) { |
child.setValueFromContext(jsonContext.get(child.getUUID())); |
} else { |
System.out.println("LightUITabbed.setValueFromContext() - Context doesn't contains value for UUID: " + child.getUUID() + " ID: " + child.getId()); |
if (jsonContext == null) { |
System.err.println("LightUITabbed.setValueFromContext() - json is null for this panel: " + this.getId()); |
} else { |
final int childCount = this.getChildrenCount(); |
for (int i = 0; i < childCount; i++) { |
final LightUITab child = this.getChild(i, LightUITab.class); |
if (jsonContext.containsKey(child.getUUID())) { |
child._setValueFromContext(jsonContext.get(child.getUUID())); |
} else { |
System.out.println("LightUITabbed.setValueFromContext() - Context doesn't contains value for UUID: " + child.getUUID() + " ID: " + child.getId()); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUserControl.java |
---|
Nouveau fichier |
0,0 → 1,46 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import net.minidev.json.JSONObject; |
public abstract class LightUserControl extends LightUIElement { |
public LightUserControl(final JSONObject json) { |
super(json); |
} |
public LightUserControl(final String id) { |
super(id); |
} |
public LightUserControl(final LightUserControl userControl) { |
super(userControl); |
} |
public void setValueFromContext(final Object value) { |
if (this.isEnabled()) { |
this._setValueFromContext(value); |
} |
} |
/** |
* Set value for all elements send by client with buttons TYPE_BUTTON_WITH_SELECTION_CONTEXT and |
* TYPE_BUTTON_WITH_CONTEXT |
* |
* @param value to set for element |
*/ |
protected abstract void _setValueFromContext(final Object value); |
public abstract Object getValueForContext(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIContainer.java |
---|
22,7 → 22,7 |
import net.minidev.json.JSONArray; |
import net.minidev.json.JSONObject; |
public abstract class LightUIContainer extends LightUIElement { |
public class LightUIContainer extends LightUIElement { |
private List<LightUIElement> children; |
public LightUIContainer(final String id) { |
46,6 → 46,15 |
child.setParent(this); |
this.children.add(child); |
} |
public void addChildren(final List<LightUIElement> children) { |
if (children == null) { |
throw new IllegalArgumentException("List null, id:" + this.getId()); |
} |
for(final LightUIElement child: children){ |
this.addChild(child); |
} |
} |
public void insertChild(final int index, final LightUIElement child) { |
if (child == null) { |
72,7 → 81,7 |
public <T extends LightUIElement> T getChild(final int index, final Class<T> expectedClass) { |
if (this.children != null) |
return (T) this.children.get(index); |
return expectedClass.cast(this.children.get(index)); |
else |
return null; |
} |
79,7 → 88,7 |
public <T extends LightUIElement> T getFirstChild(final Class<T> expectedClass) { |
if (this.getChildrenCount() > 0) |
return (T) this.children.get(0); |
return expectedClass.cast(this.children.get(0)); |
else |
return null; |
} |
104,7 → 113,7 |
final LightUIElement child = this.children.get(i); |
if (child.getId().equals(pChild.getId())) { |
this.children.set(i, pChild); |
child.setParent(this); |
pChild.setParent(this); |
return true; |
} |
if (child instanceof LightUIContainer) { |
125,7 → 134,7 |
return this.findChild(searchParam, byUUID, LightUIElement.class); |
} |
public <T extends LightUIElement> T findChild(final String searchParam, final boolean byUUID, final Class<T> childClass) { |
public <T extends LightUIElement> T findChild(final String searchParam, final boolean byUUID, final Class<T> expectedClass) { |
final int childCount = this.getChildrenCount(); |
LightUIElement result = null; |
for (int i = 0; i < childCount; i++) { |
143,7 → 152,7 |
} |
if (child instanceof LightUIContainer) { |
result = ((LightUIContainer) child).findChild(searchParam, byUUID, childClass); |
result = ((LightUIContainer) child).findChild(searchParam, byUUID, expectedClass); |
if (result != null) { |
break; |
} |
150,7 → 159,7 |
} |
if (child instanceof LightUITable) { |
result = ((LightUITable) child).findElement(searchParam, byUUID, childClass); |
result = ((LightUITable) child).findElement(searchParam, byUUID, expectedClass); |
if (result != null) { |
break; |
} |
158,15 → 167,39 |
} |
if (result != null) { |
if (childClass.isAssignableFrom(result.getClass())) { |
return (T) result; |
if (expectedClass.isAssignableFrom(result.getClass())) { |
return expectedClass.cast(result); |
} else { |
throw new InvalidClassException(childClass.getName(), result.getClass().getName(), result.getId()); |
throw new InvalidClassException(expectedClass.getName(), result.getClass().getName(), result.getId()); |
} |
} |
return null; |
} |
public <T extends LightUIElement> List<T> findChildren(final Class<T> expectedClass, final boolean recursively) { |
final List<T> result = new ArrayList<T>(); |
final int childCount = this.getChildrenCount(); |
for (int i = 0; i < childCount; i++) { |
final LightUIElement child = this.getChild(i); |
if (recursively) { |
if (child instanceof LightUIContainer) { |
result.addAll(((LightUIContainer) child).findChildren(expectedClass, true)); |
} |
if (child instanceof LightUITable) { |
result.addAll(((LightUITable) child).findChildren(expectedClass, true)); |
} |
} |
if (expectedClass.isAssignableFrom(child.getClass())) { |
result.add(expectedClass.cast(child)); |
} |
} |
return result; |
} |
@Override |
protected void copy(LightUIElement element) { |
super.copy(element); |
230,4 → 263,12 |
} |
} |
} |
@Override |
public void destroy() { |
super.destroy(); |
for (final LightUIElement child : this.children) { |
child.destroy(); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUISlider.java |
---|
Nouveau fichier |
0,0 → 1,102 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUISlider extends LightUserControl { |
Integer maxValue = 1; |
Integer minValue = 0; |
Integer increment = 1; |
public LightUISlider(final String id) { |
super(id); |
this.setType(TYPE_SLIDER); |
this.setValueType(VALUE_TYPE_INTEGER); |
this.setValue("0"); |
} |
public LightUISlider(final JSONObject json) { |
super(json); |
} |
public LightUISlider(final LightUISlider slider) { |
super(slider); |
this.maxValue = slider.maxValue; |
this.minValue = slider.minValue; |
this.increment = slider.increment; |
} |
public Integer getMaxValue() { |
return this.maxValue; |
} |
public void setMaxValue(final int maxValue) { |
this.maxValue = maxValue; |
} |
public Integer getMinValue() { |
return this.minValue; |
} |
public void setMinValue(final int minValue) { |
this.minValue = minValue; |
} |
public Integer getIncrement() { |
return this.increment; |
} |
public void setIncrement(final int increment) { |
this.increment = increment; |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put("max-value", this.maxValue); |
json.put("min-value", this.minValue); |
json.put("increment", this.increment); |
return json; |
} |
@Override |
public void fromJSON(JSONObject json) { |
super.fromJSON(json); |
this.maxValue = JSONConverter.getParameterFromJSON(json, "max-value", Integer.class, 1); |
this.minValue = JSONConverter.getParameterFromJSON(json, "min-value", Integer.class, 0); |
this.increment = JSONConverter.getParameterFromJSON(json, "increment", Integer.class, 1); |
} |
@Override |
public void _setValueFromContext(Object value) { |
if (value instanceof Number) { |
this.setValue(value.toString()); |
} else { |
throw new IllegalArgumentException("Incorrect value " + value + "type for ui element: " + this.getId()); |
} |
} |
@Override |
public Object getValueForContext() { |
if (this.getValue() == null) { |
return null; |
} else { |
return Integer.parseInt(this.getValue()); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowsBulk.java |
---|
31,6 → 31,7 |
private List<Row> rows; |
private int offset; |
private int total; |
private boolean remove; |
public RowsBulk() {// Serialization |
} |
39,10 → 40,11 |
this.fromJSON(json); |
} |
public RowsBulk(List<Row> rows, int offset, int total) { |
public RowsBulk(List<Row> rows, int offset, int total, final boolean remove) { |
this.rows = rows; |
this.offset = offset; |
this.total = total; |
this.remove = remove; |
} |
// Sending by column : size gain is 5% |
56,7 → 58,7 |
int columnCount = in.readByte(); |
// id |
for (int j = 0; j < rowCount; j++) { |
Row row = new Row(in.readLong(), columnCount); |
Row row = new Row((Number) in.readObject(), columnCount); |
this.rows.add(row); |
} |
71,6 → 73,7 |
} |
this.offset = in.readInt(); |
this.total = in.readInt(); |
this.remove = in.readBoolean(); |
} |
@Override |
86,7 → 89,7 |
// ids |
for (int j = 0; j < rowCount; j++) { |
Row row = this.rows.get(j); |
out.writeLong(row.getId()); |
out.writeObject(row.getId()); |
} |
104,20 → 107,25 |
} |
out.writeInt(this.offset); |
out.writeInt(this.total); |
out.writeBoolean(this.remove); |
} |
public List<Row> getRows() { |
public final List<Row> getRows() { |
return this.rows; |
} |
public int getOffset() { |
public final int getOffset() { |
return this.offset; |
} |
public int getTotal() { |
public final int getTotal() { |
return this.total; |
} |
public final boolean isRemove() { |
return this.remove; |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject result = new JSONObject(); |
125,20 → 133,26 |
result.put("rows", JSONConverter.getJSON(this.rows)); |
result.put("offset", this.offset); |
result.put("total", this.total); |
result.put("remove", this.remove); |
return result; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
this.offset = (Integer) JSONConverter.getParameterFromJSON(json, "offset", Integer.class); |
this.total = (Integer) JSONConverter.getParameterFromJSON(json, "total", Integer.class); |
this.offset = JSONConverter.getParameterFromJSON(json, "offset", Integer.class); |
this.total = JSONConverter.getParameterFromJSON(json, "total", Integer.class); |
final JSONArray jsonRows = (JSONArray) JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class); |
final JSONArray jsonRows = JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class); |
this.rows = new ArrayList<Row>(); |
if (jsonRows != null) { |
for (final Object o : jsonRows) { |
this.rows.add(new Row((JSONObject) JSONConverter.getObjectFromJSON(o, JSONObject.class))); |
this.rows.add(new Row(JSONConverter.getObjectFromJSON(o, JSONObject.class))); |
} |
} |
} |
@Override |
public String toString() { |
return this.rows.size() + " rows at offset " + offset + " (total:" + total + ") remove:" + this.remove; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIHourEditor.java |
---|
Nouveau fichier |
0,0 → 1,85 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUIHourEditor extends LightUserControl { |
private int hour; |
private int minute; |
public LightUIHourEditor(final JSONObject json) { |
super(json); |
} |
public LightUIHourEditor(final String id, int hour, int minute) { |
super(id); |
this.hour = hour; |
this.minute = minute; |
this.setType(TYPE_HOUR_EDITOR); |
this.setValueType(LightUIElement.VALUE_TYPE_INTEGER); |
} |
public LightUIHourEditor(LightUIHourEditor lightUIHourEditor) { |
super(lightUIHourEditor); |
this.hour = lightUIHourEditor.hour; |
this.minute = lightUIHourEditor.minute; |
} |
public int getHour() { |
return hour; |
} |
public void setHour(int hour) { |
this.hour = hour; |
} |
public int getMinute() { |
return minute; |
} |
public void setMinute(int minute) { |
this.minute = minute; |
} |
@Override |
public JSONToLightUIConvertor getConvertor() { |
return new JSONToLightUIConvertor() { |
@Override |
public LightUIElement convert(final JSONObject json) { |
return new LightUIHourEditor(json); |
} |
}; |
} |
@Override |
public Object getValueForContext() { |
return this.hour + 60 * this.minute; |
} |
@Override |
public void _setValueFromContext(Object value) { |
final Integer strValue = (Integer) JSONConverter.getObjectFromJSON(value, Integer.class); |
this.hour = strValue / 60; |
this.minute = strValue % 60; |
} |
@Override |
public LightUIElement clone() { |
return new LightUIHourEditor(this); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUICheckBox.java |
---|
15,7 → 15,7 |
import net.minidev.json.JSONObject; |
public class LightUICheckBox extends LightUIElement implements IUserControl { |
public class LightUICheckBox extends LightUserControl { |
public LightUICheckBox(final JSONObject json) { |
super(json); |
64,12 → 64,12 |
} |
@Override |
public Object getValueFromContext() { |
public Object getValueForContext() { |
return this.isChecked(); |
} |
@Override |
public void setValueFromContext(Object value) { |
public void _setValueFromContext(Object value) { |
boolean bValue = false; |
if (value != null) { |
if (value.equals("true")) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUploadWithSelection.java |
---|
Nouveau fichier |
0,0 → 1,80 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUIFileUploadWithSelection extends LightUIFileUpload { |
private static final String TABLE_ID_JSON_KEY = "table-id"; |
private String tableId; |
public LightUIFileUploadWithSelection(final JSONObject json) { |
super(json); |
} |
public LightUIFileUploadWithSelection(final LightUIFileUploadWithSelection file) { |
super(file); |
} |
public LightUIFileUploadWithSelection(final String id, final String tableId, final String sendFileUrl) { |
super(id, sendFileUrl); |
this.setType(LightUIElement.TYPE_FILE_UPLOAD_WITH_SELECTION); |
this.setGridWidth(1); |
this.tableId = tableId; |
} |
@Override |
public JSONToLightUIConvertor getConvertor() { |
return new JSONToLightUIConvertor() { |
@Override |
public LightUIElement convert(final JSONObject json) { |
return new LightUIFileUploadWithSelection(json); |
} |
}; |
} |
@Override |
public LightUIElement clone() { |
return new LightUIFileUploadWithSelection(this); |
} |
@Override |
protected void copy(LightUIElement element) { |
super.copy(element); |
if (!(element instanceof LightUIFileUploadWithSelection)) { |
throw new InvalidClassException(this.getClassName(), element.getClassName(), element.getId()); |
} |
final LightUIFileUploadWithSelection files = (LightUIFileUploadWithSelection) element; |
this.tableId = files.tableId; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.tableId = JSONConverter.getParameterFromJSON(json, TABLE_ID_JSON_KEY, String.class); |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put(TABLE_ID_JSON_KEY, this.tableId); |
return json; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextField.java |
---|
17,7 → 17,7 |
import net.minidev.json.JSONObject; |
public class LightUITextField extends LightUIElement implements IUserControl { |
public class LightUITextField extends LightUserControl { |
public LightUITextField(final String id) { |
super(id); |
this.setType(TYPE_TEXT_FIELD); |
48,13 → 48,13 |
} |
@Override |
public Object getValueFromContext() { |
return this.getValue(); |
public Object getValueForContext() { |
return (this.getValue() == null) ? null : ((this.getValue().trim().equals("")) ? null : this.getValue()); |
} |
@Override |
public void setValueFromContext(final Object value) { |
final String strValue = (String) JSONConverter.getObjectFromJSON(value, String.class); |
public void _setValueFromContext(final Object value) { |
final String strValue = JSONConverter.getObjectFromJSON(value, String.class); |
if (strValue != null && !strValue.trim().isEmpty()) { |
this.setValue(strValue); |
} else { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButtonLink.java |
---|
13,6 → 13,7 |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.io.JSONConverter; |
import java.util.HashMap; |
53,11 → 54,11 |
public void addUrlParameter(final String key, final String value) { |
this.urlParameters.put(key, value); |
} |
public void removeUrlParameter(final String key) { |
this.urlParameters.remove(key); |
} |
public void clearUrlParameter() { |
this.urlParameters.clear(); |
} |
107,6 → 108,6 |
public void fromJSON(JSONObject json) { |
super.fromJSON(json); |
this.openNewFrame = JSONConverter.getParameterFromJSON(json, OPEN_NEW_FRAME_KEY, Boolean.class, false); |
this.urlParameters = JSONConverter.getParameterFromJSON(json, URL_PARAMETER_KEY, Map.class); |
this.urlParameters = CollectionUtils.castMap(JSONConverter.getParameterFromJSON(json, URL_PARAMETER_KEY, Map.class), String.class, String.class); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIElement.java |
---|
18,13 → 18,16 |
import java.awt.Color; |
import java.io.PrintStream; |
import java.util.HashMap; |
import java.util.Map; |
import net.minidev.json.JSONObject; |
public class LightUIElement implements Transferable { |
private static final String HORIZONTALLY_RESIZABLE = "horizontally-resizable"; |
private static final String VERTICALLY_SCROLLABLE = "vertically-scrollable"; |
private static final String VERTICALLY_RESIZABLE = "vertically-resizable"; |
private static final String HORIZONTALLY_SCROLLABLE = "horizontally-scrollable"; |
public enum GlyphIcon { |
WARNING("#warning"), PLUS("#plus"), PENCIL("#pencil"), SEARCH("#search"), REMOVE("#remove"), STAR("#star"), STAR_EMPTY("#star-empty"), USER("#user"), LOCK("#lock"), UNLOCK( |
"#unlock"), DOWNLOAD("#download"), UPLOAD("#upload"); |
60,9 → 63,11 |
public static final int TYPE_DROPDOWN_BUTTON = 12; |
public static final int TYPE_FRAME = 13; |
public static final int TYPE_IMAGE = 14; |
public static final int TYPE_FILE = 15; |
public static final int TYPE_FILE_UPLOAD_WITH_SELECTION = 15; |
public static final int TYPE_PANEL_LINE = 16; |
public static final int TYPE_TAB_ELEMENT = 17; |
public static final int TYPE_SLIDER = 18; |
public static final int TYPE_PICTURE_UPLOAD = 19; |
public static final int TYPE_BUTTON = 20; |
public static final int TYPE_BUTTON_WITH_CONTEXT = 21; |
public static final int TYPE_BUTTON_CANCEL = 22; |
71,6 → 76,12 |
public static final int TYPE_BUTTON_LINK = 25; |
public static final int TYPE_RAW_HTML = 26; |
public static final int TYPE_TEXT_AREA = 27; |
public static final int TYPE_FILE_UPLOAD = 28; |
public static final int TYPE_LIST_ROW = 29; |
public static final int TYPE_BADGE = 30; |
public static final int TYPE_AUTOCOMPLETE_COMBOBOX = 31; |
public static final int TYPE_COLOR_PICKER = 32; |
public static final int TYPE_HOUR_EDITOR = 33; |
// valueType |
public static final int VALUE_TYPE_STRING = 0; |
public static final int VALUE_TYPE_INTEGER = 1; |
148,6 → 159,9 |
private boolean required = false; |
private boolean verticallyResizable = false; |
private boolean visible = true; |
private boolean notSaved = false; |
private boolean verticallyScrollable = false; |
private boolean horizontallyScrollable = false; |
private String displayPrecision;// "(1,2)" means that 0.159 is shown as 0.16 |
private String icon; |
167,8 → 181,6 |
private LightUIElement parent; |
private Map<Integer, String> actions = new HashMap<Integer, String>(); |
public LightUIElement(final String id) { |
this.id = id; |
this.UUID = java.util.UUID.randomUUID().toString(); |
431,6 → 443,14 |
this.readOnly = readOnly; |
} |
public boolean isNotSaved() { |
return this.notSaved; |
} |
public void setNotSaved(boolean notSaved) { |
this.notSaved = notSaved; |
} |
public Color getBackgroundColor() { |
return this.backgroundColor; |
} |
563,28 → 583,44 |
return this.verticallyResizable; |
} |
public final void setVerticalyResizable(boolean verticallyResizable) { |
public final void setVerticallyResizable(boolean verticallyResizable) { |
this.verticallyResizable = verticallyResizable; |
} |
public final boolean isHorizontalyResizable() { |
public final boolean isHorizontallyResizable() { |
return this.horizontallyResizable; |
} |
public final void setHorizontalyResizable(boolean horizontallyResizable) { |
public final void setHorizontallyResizable(boolean horizontallyResizable) { |
this.horizontallyResizable = horizontallyResizable; |
} |
public final boolean isHorizontallyScrollable() { |
return this.horizontallyScrollable; |
} |
public final void setHorizontallyScrollable(boolean horizontallyScrollable) { |
this.horizontallyScrollable = horizontallyScrollable; |
} |
public final boolean isVerticallyScrollable() { |
return this.verticallyScrollable; |
} |
public final void setVerticallyScrollable(boolean verticallyScrollable) { |
this.verticallyScrollable = verticallyScrollable; |
} |
public final LightUIElement getParent() { |
return this.parent; |
} |
public final <T extends LightUIContainer> T getParent(final Class<T> classExpected) { |
public final <T extends LightUIElement> T getParent(final Class<T> expectedClass) { |
LightUIElement parent = this.parent; |
while (parent != null && !classExpected.isAssignableFrom(parent.getClass())) { |
while (parent != null && !expectedClass.isAssignableFrom(parent.getClass())) { |
parent = parent.getParent(); |
} |
return (T) parent; |
return expectedClass.cast(parent); |
} |
public void setParent(LightUIElement parent) { |
591,14 → 627,6 |
this.parent = parent; |
} |
public final Map<Integer, String> getActions() { |
return this.actions; |
} |
public final void addAction(final Integer actionType, final String actionId) { |
this.actions.put(actionType, actionId); |
} |
public void dump(PrintStream out, final int depth) { |
final String type = this.getTypeAsString(); |
String valueType = "?"; |
689,13 → 717,13 |
} |
protected void addSpacer(PrintStream out, int depth) { |
protected final void addSpacer(PrintStream out, int depth) { |
for (int i = 0; i < depth; i++) { |
out.print(" "); |
} |
} |
public String getTypeAsString() { |
public final String getTypeAsString() { |
String type = "?"; |
if (this.type == TYPE_CHECKBOX) { |
type = "checkbox"; |
708,7 → 736,7 |
} else if (this.type == TYPE_TEXT_FIELD) { |
type = "textfield"; |
} else if (this.type == TYPE_TABLE) { |
type = "list"; |
type = "table"; |
} else if (this.type == TYPE_TABBED_UI) { |
type = "tabs"; |
} else if (this.type == TYPE_TREE) { |
723,8 → 751,8 |
type = "combo element"; |
} else if (this.type == TYPE_BUTTON_WITH_SELECTION_CONTEXT) { |
type = "button with selection context"; |
} else if (this.type == TYPE_FILE) { |
type = "file"; |
} else if (this.type == TYPE_FILE_UPLOAD_WITH_SELECTION) { |
type = "file upload with selection"; |
} else if (this.type == TYPE_FRAME) { |
type = "frame"; |
} else if (this.type == TYPE_DROPDOWN_BUTTON) { |
735,6 → 763,12 |
type = "list"; |
} else if (this.type == TYPE_RAW_HTML) { |
type = "raw html"; |
} else if (this.type == TYPE_SLIDER) { |
type = "slider"; |
} else if (this.type == TYPE_PICTURE_UPLOAD) { |
type = "picture upload"; |
} else if (this.type == TYPE_FILE_UPLOAD) { |
type = "file upload"; |
} |
return type; |
784,15 → 818,19 |
this.enabled = element.enabled; |
this.fillWidth = element.fillWidth; |
this.fillHeight = element.fillHeight; |
this.foldable = element.foldable; |
this.folded = element.folded; |
this.fontBold = element.fontBold; |
this.fontItalic = element.fontItalic; |
this.horizontallyResizable = element.horizontallyResizable; |
this.horizontallyScrollable = element.horizontallyScrollable; |
this.required = element.required; |
this.readOnly = element.readOnly; |
this.verticallyResizable = element.verticallyResizable; |
this.verticallyScrollable = element.verticallyScrollable; |
this.visible = element.visible; |
this.notSaved = element.notSaved; |
this.displayPrecision = element.displayPrecision; |
this.icon = element.icon; |
806,9 → 844,6 |
this.borderColor = element.borderColor; |
this.cellBackgroundColor = element.cellBackgroundColor; |
this.foreColor = element.foreColor; |
this.actions = element.actions; |
} |
@Override |
905,6 → 940,9 |
if (this.fillWidth) { |
result.put("fill-width", true); |
} |
if (this.fillHeight) { |
result.put("fill-height", true); |
} |
if (this.foldable) { |
result.put("foldable", true); |
} |
918,8 → 956,11 |
result.put("italic", true); |
} |
if (this.horizontallyResizable) { |
result.put("horizontally-resizable", true); |
result.put(HORIZONTALLY_RESIZABLE, true); |
} |
if (this.horizontallyScrollable) { |
result.put(HORIZONTALLY_SCROLLABLE, true); |
} |
if (this.required) { |
result.put("required", true); |
} |
927,11 → 968,17 |
result.put("read-only", true); |
} |
if (this.verticallyResizable) { |
result.put("vertically-resizable", true); |
result.put(VERTICALLY_RESIZABLE, true); |
} |
if (this.verticallyScrollable) { |
result.put(VERTICALLY_SCROLLABLE, true); |
} |
if (!this.visible) { |
result.put("visible", false); |
} |
if (this.notSaved) { |
result.put("not-saved", true); |
} |
if (this.displayPrecision != null) { |
result.put("display-precision", this.displayPrecision); |
970,10 → 1017,6 |
result.put("fore-color", JSONConverter.getJSON(this.foreColor)); |
} |
if (!this.actions.isEmpty()) { |
result.put("actions", this.actions); |
} |
return result; |
} |
1021,11 → 1064,14 |
this.fillWidth = JSONConverter.getParameterFromJSON(json, "fill-width", Boolean.class, false); |
this.fontBold = JSONConverter.getParameterFromJSON(json, "bold", Boolean.class, false); |
this.fontItalic = JSONConverter.getParameterFromJSON(json, "italic", Boolean.class, false); |
this.horizontallyResizable = JSONConverter.getParameterFromJSON(json, "horizontally-resizable", Boolean.class, false); |
this.verticallyResizable = JSONConverter.getParameterFromJSON(json, "vertically-resizable", Boolean.class, false); |
this.horizontallyResizable = JSONConverter.getParameterFromJSON(json, HORIZONTALLY_RESIZABLE, Boolean.class, false); |
this.horizontallyScrollable = JSONConverter.getParameterFromJSON(json, HORIZONTALLY_SCROLLABLE, Boolean.class, false); |
this.verticallyResizable = JSONConverter.getParameterFromJSON(json, VERTICALLY_RESIZABLE, Boolean.class, false); |
this.verticallyScrollable = JSONConverter.getParameterFromJSON(json, VERTICALLY_SCROLLABLE, Boolean.class, false); |
this.required = JSONConverter.getParameterFromJSON(json, "required", Boolean.class, false); |
this.readOnly = JSONConverter.getParameterFromJSON(json, "read-only", Boolean.class, false); |
this.visible = JSONConverter.getParameterFromJSON(json, "visible", Boolean.class, true); |
this.notSaved = JSONConverter.getParameterFromJSON(json, "not-saved", Boolean.class, false); |
this.backgroundColor = JSONConverter.getParameterFromJSON(json, "background-color", Color.class); |
this.borderColor = JSONConverter.getParameterFromJSON(json, "border-color", Color.class); |
1032,4 → 1078,8 |
this.cellBackgroundColor = JSONConverter.getParameterFromJSON(json, "cell-background-color", Color.class); |
this.foreColor = JSONConverter.getParameterFromJSON(json, "fore-color", Color.class); |
} |
public void destroy() { |
this.setValue(null); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFrame.java |
---|
23,10 → 23,14 |
import net.minidev.json.JSONObject; |
public class LightUIFrame extends LightUIContainer { |
private static final String ACTIVE = "active"; |
private static final String TITLE_PANEL = "title-panel"; |
private static final String FOOTER_PANEL = "footer-panel"; |
private static final String CHILDREN_FRAME = "children-frame"; |
private Boolean active = false; |
private String title; |
private final LightUIPanel footerPanel = new LightUIPanel(this.getId() + ".footer.panel"); |
private LightUIPanel titlePanel = null; |
private LightUIPanel footerPanel = new LightUIPanel(this.getId() + ".footer.panel"); |
private List<LightUIFrame> childrenFrame; |
39,9 → 43,10 |
public LightUIFrame(final LightUIFrame frame) { |
super(frame); |
this.active = frame.active; |
this.title = frame.title; |
this.footerPanel.copy(frame.footerPanel); |
this.titlePanel = frame.titlePanel; |
this.childrenFrame = frame.childrenFrame; |
this.setFooterPanel(frame.footerPanel); |
} |
/** |
56,20 → 61,49 |
this.childrenFrame = new ArrayList<LightUIFrame>(); |
this.addChild(new LightUIPanel(this.getId() + ".main.panel")); |
this.footerPanel.setParent(this); |
this.footerPanel.setFillHeight(false); |
this.footerPanel.setHeight(50); |
this.createTitlePanel(); |
} |
public String getTitle() { |
return this.title; |
public LightUIPanel createTitlePanel(final String title) { |
this.createTitlePanel(); |
final LightUILabel titleLabel = new LightUILabel(this.titlePanel.getId() + ".label", title, true); |
titleLabel.setVerticalAlignement(VALIGN_CENTER); |
this.titlePanel.getLastLine().addChild(titleLabel); |
return this.titlePanel; |
} |
public void setTitle(final String title) { |
this.title = title; |
public LightUIPanel createTitlePanel() { |
this.titlePanel = new LightUIPanel(this.getId() + ".title.panel"); |
this.titlePanel.setFillHeight(false); |
this.titlePanel.setHeight(50); |
return this.titlePanel; |
} |
public LightUIPanel getTitlePanel() { |
return this.titlePanel; |
} |
public LightUIPanel getFooterPanel() { |
return this.footerPanel; |
} |
/** |
* Set the footer panel of the frame, be careful the ID is automatically replace by |
* <code>this.getId() + ".footer.panel"</code>. |
* |
* @param footerPanel - The new footer panel of this frame. |
*/ |
public void setFooterPanel(final LightUIPanel footerPanel) { |
footerPanel.setId(this.getId() + ".footer.panel"); |
this.footerPanel = footerPanel; |
this.footerPanel.setFillHeight(false); |
this.footerPanel.setParent(this); |
this.footerPanel.setHeight(50); |
} |
public void updateFooterPanel(final LightUIPanel footerPanel) { |
if (footerPanel != null) { |
this.footerPanel.copy(footerPanel); |
207,12 → 241,12 |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
if (this.active) { |
json.put("active", true); |
json.put(ACTIVE, true); |
} |
if (this.title != null) { |
json.put("title", this.title); |
if (this.titlePanel != null) { |
json.put(TITLE_PANEL, this.titlePanel.toJSON()); |
} |
json.put("footer-panel", this.footerPanel.toJSON()); |
json.put(FOOTER_PANEL, this.footerPanel.toJSON()); |
return json; |
} |
219,15 → 253,19 |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.active = (Boolean) JSONConverter.getParameterFromJSON(json, "active", Boolean.class, false); |
this.title = (String) JSONConverter.getParameterFromJSON(json, "title", String.class); |
this.active = JSONConverter.getParameterFromJSON(json, ACTIVE, Boolean.class, false); |
final JSONObject jsonFooterPanel = (JSONObject) JSONConverter.getParameterFromJSON(json, "footer-panel", JSONObject.class, null); |
final JSONObject jsonTitlePanel = JSONConverter.getParameterFromJSON(json, TITLE_PANEL, JSONObject.class); |
if (jsonTitlePanel != null) { |
this.titlePanel.fromJSON(jsonTitlePanel); |
} |
final JSONObject jsonFooterPanel = (JSONObject) JSONConverter.getParameterFromJSON(json, FOOTER_PANEL, JSONObject.class, null); |
if (jsonFooterPanel != null) { |
this.footerPanel.fromJSON(jsonFooterPanel); |
} |
final JSONArray jsonChildrenFrame = (JSONArray) JSONConverter.getParameterFromJSON(json, "children-frame", JSONArray.class, null); |
final JSONArray jsonChildrenFrame = (JSONArray) JSONConverter.getParameterFromJSON(json, CHILDREN_FRAME, JSONArray.class, null); |
this.childrenFrame = new ArrayList<LightUIFrame>(); |
if (jsonChildrenFrame != null) { |
for (final Object objJsonFrame : jsonChildrenFrame) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowSpec.java |
---|
19,6 → 19,7 |
import java.io.ObjectOutput; |
import java.util.List; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.io.JSONAble; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONArray; |
105,7 → 106,7 |
if (jsonColumnIds != null) { |
try { |
this.columnIds = new String[jsonColumnIds.size()]; |
this.columnIds = ((List<String>) (List<?>) jsonColumnIds).toArray(this.columnIds); |
this.columnIds = CollectionUtils.castList((List<?>) jsonColumnIds, String.class).toArray(this.columnIds); |
} catch (final Exception ex) { |
throw new IllegalArgumentException("invalid value for 'possible-column-ids', List<String> expected"); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPanel.java |
---|
24,11 → 24,10 |
import net.minidev.json.JSONArray; |
import net.minidev.json.JSONObject; |
public class LightUIPanel extends LightUIContainer implements Transferable, IUserControlContainer { |
public class LightUIPanel extends LightUserControlContainer implements Transferable { |
private static final long serialVersionUID = -3399395824294128572L; |
private String title; |
private boolean verticallyScrollable = false; |
private Color titleColor; |
private Color titleBackgroundColor; |
49,6 → 48,7 |
this.setType(TYPE_PANEL); |
this.setWeightX(1); |
this.setFillWidth(true); |
this.setFillHeight(true); |
} |
public final LightUILine getLastLine() { |
70,14 → 70,6 |
this.title = title; |
} |
public boolean isVerticallyScrollable() { |
return this.verticallyScrollable; |
} |
public void setVerticallyScrollable(final boolean verticallyScrollable) { |
this.verticallyScrollable = verticallyScrollable; |
} |
public void setTitleColor(final Color c) { |
this.titleColor = c; |
} |
130,7 → 122,6 |
} |
final LightUIPanel panelElement = (LightUIPanel) element; |
this.title = panelElement.title; |
this.verticallyScrollable = panelElement.verticallyScrollable; |
this.titleColor = panelElement.titleColor; |
this.titleBackgroundColor = panelElement.titleBackgroundColor; |
this.controlers.addAll(panelElement.controlers); |
184,7 → 175,7 |
this.addSpacer(out, depth); |
out.println("Title : " + this.title); |
this.addSpacer(out, depth); |
out.println("v-scroll : " + this.verticallyScrollable + " title-color: " + this.titleColor.toString() + " bg-title-color: " + this.titleBackgroundColor.toString()); |
out.println("v-scroll : " + this.isVerticallyScrollable() + " title-color: " + this.titleColor.toString() + " bg-title-color: " + this.titleBackgroundColor.toString()); |
super.dump(out, depth); |
this.addSpacer(out, depth); |
out.println("------------------------"); |
191,24 → 182,29 |
} |
@Override |
public void setValueFromContext(final Object value) { |
public void _setValueFromContext(final Object value) { |
final JSONObject jsonContext = (JSONObject) JSONConverter.getObjectFromJSON(value, JSONObject.class); |
final int childCount = this.getChildrenCount(); |
for (int i = 0; i < childCount; i++) { |
final LightUILine line = this.getChild(i, LightUILine.class); |
final int lineChildCount = line.getChildrenCount(); |
for (int j = 0; j < lineChildCount; j++) { |
final LightUIElement lineChild = line.getChild(j); |
if (lineChild instanceof IUserControlContainer) { |
if (!jsonContext.containsKey(lineChild.getUUID())) { |
throw new IllegalArgumentException("Impossible to find key " + lineChild.getUUID() + " in context, LightUIElement id: " + lineChild.getId()); |
if (jsonContext == null) { |
System.err.println("LightUIPanel.setValueFromContext() - json is null for this panel: " + this.getId()); |
} else { |
final int childCount = this.getChildrenCount(); |
for (int i = 0; i < childCount; i++) { |
final LightUILine line = this.getChild(i, LightUILine.class); |
final int lineChildCount = line.getChildrenCount(); |
for (int j = 0; j < lineChildCount; j++) { |
final LightUIElement lineChild = line.getChild(j); |
if (lineChild instanceof LightUserControlContainer) { |
if (!jsonContext.containsKey(lineChild.getUUID())) { |
System.err.println("LightUIPanel.setValueFromContext() - Impossible to find key " + lineChild.getUUID() + " in context, LightUIElement id: " + lineChild.getId()); |
} |
((LightUserControlContainer) lineChild).setValueFromContext(jsonContext.get(lineChild.getUUID())); |
} else if (lineChild instanceof LightUserControl) { |
if (!jsonContext.containsKey(lineChild.getUUID())) { |
System.err.println("LightUIPanel.setValueFromContext() - Impossible to find key " + lineChild.getUUID() + " in context, LightUIElement id: " + lineChild.getId()); |
} |
((LightUserControl) lineChild).setValueFromContext(jsonContext.get(lineChild.getUUID())); |
} |
((IUserControlContainer) lineChild).setValueFromContext(jsonContext.get(lineChild.getUUID())); |
} else if (lineChild instanceof IUserControl) { |
if (!jsonContext.containsKey(lineChild.getUUID())) { |
throw new IllegalArgumentException("Impossible to find key " + lineChild.getUUID() + " in context, LightUIElement id: " + lineChild.getId()); |
} |
((IUserControl) lineChild).setValueFromContext(jsonContext.get(lineChild.getUUID())); |
} |
} |
} |
231,9 → 227,6 |
if (this.titleBackgroundColor != null) { |
result.put("title-bgcolor", JSONConverter.getJSON(this.titleBackgroundColor)); |
} |
if (this.verticallyScrollable) { |
result.put("vertically-scrollable", true); |
} |
if (!this.controlers.isEmpty()) { |
result.put("controlers", JSONConverter.getJSON(this.controlers)); |
} |
245,7 → 238,6 |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.title = (String) JSONConverter.getParameterFromJSON(json, "title", String.class, null); |
this.verticallyScrollable = (Boolean) JSONConverter.getParameterFromJSON(json, "vertically-scrollable", Boolean.class, false); |
this.titleColor = (Color) JSONConverter.getParameterFromJSON(json, "title-color", Color.class, null); |
this.titleBackgroundColor = (Color) JSONConverter.getParameterFromJSON(json, "title-bgcolor", Color.class, null); |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/RowSelectionSpec.java |
---|
20,6 → 20,7 |
import java.util.ArrayList; |
import java.util.List; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.io.JSONAble; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONArray; |
28,7 → 29,7 |
public class RowSelectionSpec implements Externalizable, JSONAble { |
private String tableId; |
private List<Long> ids; |
private List<Number> ids; |
/** |
* Define selected ids of a table. ids are ids from selected lines |
40,31 → 41,31 |
public RowSelectionSpec(final JSONObject json) { |
this.fromJSON(json); |
} |
public RowSelectionSpec(String tableId, List<Long> ids) { |
this.init(tableId, ids); |
} |
public RowSelectionSpec(String tableId) { |
this.init(tableId, null); |
this(tableId, new ArrayList<Number>()); |
} |
private void init(final String tableId, final List<Long> ids) { |
public RowSelectionSpec(final String tableId, final List<Number> selectedIds) { |
this.tableId = tableId; |
if (ids != null) { |
this.ids = ids; |
} else { |
this.ids = new ArrayList<Long>(); |
} |
this.ids = selectedIds; |
} |
public List<Long> getIds() { |
public final List<Number> getIds() { |
return this.ids; |
} |
public final void setIds(List<Number> ids) { |
this.ids = ids; |
} |
public String getTableId() { |
return this.tableId; |
} |
public boolean hasSelectedId(){ |
return this.getIds() != null && !this.getIds().isEmpty(); |
} |
@Override |
public String toString() { |
95,7 → 96,7 |
@Override |
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
this.tableId = in.readUTF(); |
this.ids = (List<Long>) in.readObject(); |
this.ids = CollectionUtils.castList((List<?>) in.readObject(), Number.class); |
} |
110,11 → 111,11 |
@Override |
public void fromJSON(JSONObject json) { |
this.tableId = (String) JSONConverter.getParameterFromJSON(json, "table-id", String.class); |
final JSONArray jsonIds = (JSONArray) JSONConverter.getParameterFromJSON(json, "ids", JSONArray.class); |
this.ids = new ArrayList<Long>(); |
this.tableId = JSONConverter.getParameterFromJSON(json, "table-id", String.class); |
final JSONArray jsonIds = JSONConverter.getParameterFromJSON(json, "ids", JSONArray.class); |
this.ids = new ArrayList<Number>(); |
for (final Object jsonId : jsonIds) { |
this.ids.add((Long) JSONConverter.getObjectFromJSON(jsonId, Long.class)); |
this.ids.add(JSONConverter.getObjectFromJSON(jsonId, Number.class)); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/IntValueConvertor.java |
---|
23,13 → 23,17 |
public IntValueConvertor(final boolean hasNotSpecified) { |
super(hasNotSpecified); |
} |
@Override |
public void fillComboWithValue(final LightUIComboBox combo) { |
for(final Entry<Integer, String> entry : this.values.entrySet()) { |
public void fillComboWithValue(final LightUIComboBox combo, final Integer selectedValue) { |
for (final Entry<Integer, String> entry : this.values.entrySet()) { |
final LightUIComboBoxElement comboElement = new LightUIComboBoxElement(entry.getKey()); |
comboElement.setValue1(entry.getValue()); |
combo.addValue(comboElement); |
if (entry.getKey().equals(selectedValue)) { |
combo.setSelectedValue(comboElement); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ComboValueConvertor.java |
---|
36,19 → 36,31 |
protected abstract void init(); |
public boolean hasNotSpecifiedLine() { |
public final boolean hasNotSpecifiedLine() { |
return this.hasNotSpecifedLine; |
} |
public void fillCombo(final LightUIComboBox combo) { |
public final void fillCombo(final LightUIComboBox combo, final K selectedValue) { |
if (this.hasNotSpecifedLine) { |
combo.addValue(LightUIComboBox.getDefaultValue()); |
} |
this.fillComboWithValue(combo); |
combo.setFillFromConvertor(true); |
this.fillComboWithValue(combo, selectedValue); |
if (selectedValue == null) { |
combo.setSelectedValue(null); |
} |
if(!combo.hasSelectedValue()){ |
if(combo.hasNotSpecifedLine()){ |
combo.setSelectedValue(LightUIComboBox.getDefaultValue()); |
} else if(!combo.getValues().isEmpty()) { |
combo.setSelectedValue(combo.getValues().get(0)); |
} |
} |
combo.setAlreadyFilled(true); |
} |
protected abstract void fillComboWithValue(final LightUIComboBox combo); |
protected abstract void fillComboWithValue(final LightUIComboBox combo, final K selectedValue); |
@Override |
public String convert(final K key) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboBox.java |
---|
22,24 → 22,19 |
import net.minidev.json.JSONArray; |
import net.minidev.json.JSONObject; |
public class LightUIComboBox extends LightUIElement implements IUserControl { |
public static final int TYPE_COMBO_STANDARD = 1; |
public static final int TYPE_COMBO_AUTOCOMPLETE = 2; |
public static final int TYPE_COMBO_AUTOCOMPLETE_WITH_ACTION = 3; |
public class LightUIComboBox extends LightUserControl { |
private static final String HAS_NOT_SPECIFIED_LINE = "has-not-specified-line"; |
private static final String VALUES = "values"; |
private static final String SELECTED_VALUE = "selected-value"; |
private static final String ALREADY_FILLED = "already-filled"; |
public static final int COMBO_ACTION_SEARCH = 1; |
public static final int COMBO_ACTION_ADD = 2; |
public static final int COMBO_ACTION_MODIFY = 3; |
private boolean alreadyFilled = false; |
private boolean hasNotSpecifedLine = false; |
private int comboType = TYPE_COMBO_STANDARD; |
private boolean fillFromConvertor = false; |
private LightUIComboBoxElement selectedValue = null; |
private List<LightUIComboBoxElement> values = new ArrayList<LightUIComboBoxElement>(); |
private LightUIComboBoxElement selectedValue = null; |
private List<Integer> comboActions = new ArrayList<Integer>(); |
// Init from json constructor |
public LightUIComboBox(final JSONObject json) { |
super(json); |
55,14 → 50,6 |
this.setType(TYPE_COMBOBOX); |
} |
public int getComboType() { |
return this.comboType; |
} |
public void setComboType(final int comboType) { |
this.comboType = comboType; |
} |
public void addValue(final LightUIComboBoxElement values) { |
this.values.add(values); |
} |
71,14 → 58,6 |
this.values.addAll(values); |
} |
public List<Integer> getComboActions() { |
return this.comboActions; |
} |
public void addComboAction(final Integer comboAction) { |
this.comboActions.add(comboAction); |
} |
public static LightUIComboBoxElement getDefaultValue() { |
final String defaultLabelKey = "not.specified.label"; |
final String defaultLabel = TranslationManager.getInstance().getTranslationForItem(defaultLabelKey); |
97,8 → 76,9 |
return this.values; |
} |
// if id=0 means this is the not specifed line |
public boolean hasSelectedValue() { |
return this.selectedValue != null && this.selectedValue.getId() != 0; |
return this.selectedValue != null && ((this.hasNotSpecifedLine && this.selectedValue.getId() != 0) || !this.hasNotSpecifedLine); |
} |
public LightUIComboBoxElement getSelectedValue() { |
114,14 → 94,35 |
this.values.clear(); |
} |
public void setFillFromConvertor(final boolean fillFromConvertor) { |
this.fillFromConvertor = fillFromConvertor; |
public void setAlreadyFilled(final boolean alreadyFilled) { |
this.alreadyFilled = alreadyFilled; |
} |
public boolean isFillFromConvertor() { |
return this.fillFromConvertor; |
public boolean isAlreadyFilled() { |
return this.alreadyFilled; |
} |
public void setHasNotSpecifedLine(final boolean hasNotSpecifedLine) { |
this.hasNotSpecifedLine = hasNotSpecifedLine; |
} |
public boolean hasNotSpecifedLine() { |
return this.hasNotSpecifedLine; |
} |
public void setSelectedId(final Integer id) { |
if (id == null) { |
this.setSelectedValue(null); |
} else { |
for (final LightUIComboBoxElement value : this.values) { |
if (value.getId() == id) { |
this.setSelectedValue(value); |
break; |
} |
} |
} |
} |
@Override |
protected void copy(LightUIElement element) { |
super.copy(element); |
131,11 → 132,9 |
} |
final LightUIComboBox combo = (LightUIComboBox) element; |
this.comboType = combo.comboType; |
this.fillFromConvertor = combo.fillFromConvertor; |
this.alreadyFilled = combo.alreadyFilled; |
this.values = combo.values; |
this.selectedValue = combo.selectedValue; |
this.comboActions = combo.comboActions; |
} |
@Override |
162,17 → 161,17 |
for (final LightUIComboBoxElement value : this.values) { |
jsonValues.add(value.toJSON()); |
} |
json.put("values", jsonValues); |
json.put(VALUES, jsonValues); |
} |
if (this.comboType != TYPE_COMBO_STANDARD) { |
json.put("combo-type", this.comboType); |
if (this.alreadyFilled) { |
json.put(ALREADY_FILLED, true); |
} |
if (this.fillFromConvertor) { |
json.put("fill-from-convertor", true); |
if (this.hasNotSpecifedLine) { |
json.put(HAS_NOT_SPECIFIED_LINE, true); |
} |
if (this.selectedValue != null) { |
json.put("selected-value", this.selectedValue.toJSON()); |
json.put(SELECTED_VALUE, this.selectedValue.toJSON()); |
} |
return json; |
182,27 → 181,25 |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.comboType = (Integer) JSONConverter.getParameterFromJSON(json, "combo-type", Integer.class, TYPE_COMBO_STANDARD); |
this.fillFromConvertor = (Boolean) JSONConverter.getParameterFromJSON(json, "fill-from-convertor", Boolean.class, false); |
final JSONObject jsonSelectedValue = (JSONObject) JSONConverter.getParameterFromJSON(json, "", JSONObject.class); |
this.alreadyFilled = JSONConverter.getParameterFromJSON(json, ALREADY_FILLED, Boolean.class, false); |
this.hasNotSpecifedLine = JSONConverter.getParameterFromJSON(json, HAS_NOT_SPECIFIED_LINE, Boolean.class, false); |
final JSONObject jsonSelectedValue = JSONConverter.getParameterFromJSON(json, "", JSONObject.class); |
if (jsonSelectedValue != null) { |
this.selectedValue = new LightUIComboBoxElement(jsonSelectedValue); |
} |
final JSONArray jsonValues = (JSONArray) JSONConverter.getParameterFromJSON(json, "values", JSONArray.class); |
final JSONArray jsonValues = JSONConverter.getParameterFromJSON(json, VALUES, JSONArray.class); |
this.values = new ArrayList<LightUIComboBoxElement>(); |
if (jsonValues != null) { |
for (final Object jsonValue : jsonValues) { |
if (!(jsonValue instanceof JSONObject)) { |
throw new IllegalArgumentException("value for 'values' is invalid"); |
} |
this.values.add(new LightUIComboBoxElement((JSONObject) jsonValue)); |
this.values.add(new LightUIComboBoxElement(JSONConverter.getObjectFromJSON(jsonValue, JSONObject.class))); |
} |
} |
} |
@Override |
public Object getValueFromContext() { |
public Object getValueForContext() { |
if (this.hasSelectedValue()) { |
return this.getSelectedValue(); |
} else { |
211,12 → 208,18 |
} |
@Override |
public void setValueFromContext(Object value) { |
public void _setValueFromContext(Object value) { |
if (value != null) { |
final JSONObject jsonSelectedValue = (JSONObject) JSONConverter.getObjectFromJSON(value, JSONObject.class); |
final JSONObject jsonSelectedValue = JSONConverter.getObjectFromJSON(value, JSONObject.class); |
this.selectedValue = new LightUIComboBoxElement(jsonSelectedValue); |
} else { |
this.selectedValue = null; |
} |
} |
@Override |
public void destroy() { |
super.destroy(); |
this.clearValues(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIList.java |
---|
11,31 → 11,13 |
* When distributing the software, include this License Header Notice in each file. |
*/ |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.utils.ui.StringWithId; |
import java.util.ArrayList; |
import net.minidev.json.JSONArray; |
import net.minidev.json.JSONObject; |
public class LightUIList extends LightUIElement { |
private ArrayList<StringWithId> values = new ArrayList<StringWithId>(); |
public class LightUIList extends LightUIContainer { |
// Init from json constructor |
public LightUIList(final JSONObject json) { |
45,65 → 27,19 |
// Clone constructor |
public LightUIList(final LightUIList listElement) { |
super(listElement); |
this.values = listElement.values; |
} |
public LightUIList(final String id, final ArrayList<StringWithId> values) { |
public LightUIList(final String id) { |
super(id); |
this.setType(TYPE_LIST); |
this.values = values; |
} |
public ArrayList<StringWithId> getValues() { |
return (ArrayList<StringWithId>) this.values.clone(); |
} |
public LightUIList(final String id, final ArrayList<LightUIListRow> rows) { |
super(id); |
this.setType(TYPE_LIST); |
@Override |
public JSONToLightUIConvertor getConvertor() { |
return new JSONToLightUIConvertor() { |
@Override |
public LightUIElement convert(final JSONObject json) { |
return new LightUIList(json); |
} |
}; |
} |
@Override |
public LightUIElement clone() { |
return new LightUIList(this); |
} |
@Override |
protected void copy(LightUIElement element) { |
super.copy(element); |
if (!(element instanceof LightUIList)) { |
throw new InvalidClassException(this.getClassName(), element.getClassName(), element.getId()); |
for (final LightUIListRow row : rows) { |
this.addChild(row); |
} |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put("class", "LightUIList"); |
if (this.values != null && this.values.size() > 0) { |
json.put("values", this.values); |
} |
return json; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
final JSONArray jsonValues = (JSONArray) JSONConverter.getParameterFromJSON(json, "values", JSONArray.class); |
this.values = new ArrayList<StringWithId>(); |
if (jsonValues != null) { |
for (final Object jsonValue : jsonValues) { |
if (!(jsonValue instanceof JSONObject)) { |
throw new IllegalArgumentException("values of list must be json of StringWithId"); |
} |
this.values.add(new StringWithId((JSONObject) jsonValue)); |
} |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIColorPicker.java |
---|
Nouveau fichier |
0,0 → 1,57 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import java.awt.Color; |
import net.minidev.json.JSONObject; |
public class LightUIColorPicker extends LightUserControl { |
public LightUIColorPicker(final String id) { |
super(id); |
this.setType(TYPE_COLOR_PICKER); |
this.setBorderColor(Color.BLACK); |
} |
public LightUIColorPicker(final JSONObject json) { |
super(json); |
} |
public LightUIColorPicker(final LightUIColorPicker element) { |
super(element); |
} |
public void setSelectedColor(final Color color) { |
this.setValue(String.valueOf(color.getRGB())); |
} |
public Color getSelectedColor() { |
if (this.getValue() == null || this.getValue().isEmpty()) { |
return null; |
} else { |
return Color.decode(this.getValue()); |
} |
} |
@Override |
protected void _setValueFromContext(final Object value) { |
this.setValue((String) value); |
} |
@Override |
public Object getValueForContext() { |
return this.getValue(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIDate.java |
---|
21,7 → 21,7 |
import net.minidev.json.JSONObject; |
public class LightUIDate extends LightUIElement implements IUserControl { |
public class LightUIDate extends LightUserControl { |
public LightUIDate(final JSONObject json) { |
super(json); |
60,12 → 60,12 |
} |
@Override |
public Object getValueFromContext() { |
public Object getValueForContext() { |
return this.getValueAsDate(); |
} |
@Override |
public void setValueFromContext(Object value) { |
public void _setValueFromContext(Object value) { |
final String strValue = (String) JSONConverter.getObjectFromJSON(value, String.class); |
this.setValue(strValue); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIPictureUpload.java |
---|
Nouveau fichier |
0,0 → 1,53 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUIPictureUpload extends LightUIFileUpload { |
private static final String FILE_PATH = "file-path"; |
private String filePath = null; |
public LightUIPictureUpload(final String id, final String sendFileUrl) { |
super(id, sendFileUrl); |
this.setType(TYPE_PICTURE_UPLOAD); |
} |
public String getFilePath() { |
return this.filePath; |
} |
public void setFilePath(final String filePath) { |
this.filePath = filePath; |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
if (this.filePath != null) { |
json.put(FILE_PATH, this.filePath); |
} |
return json; |
} |
@Override |
public void fromJSON(JSONObject json) { |
super.fromJSON(json); |
this.filePath = JSONConverter.getParameterFromJSON(json, FILE_PATH, String.class); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/Row.java |
---|
13,9 → 13,9 |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.io.JSONAble; |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.utils.ui.StringWithId; |
import java.io.Externalizable; |
import java.io.IOException; |
29,10 → 29,10 |
public class Row implements Externalizable, JSONAble { |
private long id; |
private Number id; |
private String extendId; |
private List<Object> values; |
private Boolean fillWidth = false; |
private Boolean toggleable = false; |
private Boolean visible = true; |
45,79 → 45,75 |
this.fromJSON(json); |
} |
public Row(long id, int valueCount) { |
public Row(final Number id, int valueCount) { |
this.id = id; |
this.values = new ArrayList<Object>(); |
if (valueCount > 0) { |
for(int i = 0; i < valueCount; i++) { |
for (int i = 0; i < valueCount; i++) { |
this.values.add(null); |
} |
} |
} |
public Row(long id) { |
public Row(final Number id) { |
this.id = id; |
} |
public void setId(final long id) { |
this.id = id; |
} |
public void setValues(List<Object> values) { |
public final void setValues(List<Object> values) { |
this.values = values; |
} |
public List<Object> getValues() { |
public final List<Object> getValues() { |
return this.values; |
} |
public long getId() { |
public final Number getId() { |
return this.id; |
} |
public String getExtendId() { |
public final String getExtendId() { |
return this.extendId; |
} |
public void setExtendId(final String extendId) { |
public final void setExtendId(final String extendId) { |
this.extendId = extendId; |
} |
public void addValue(Object v) { |
public final void addValue(Object v) { |
this.values.add(v); |
} |
public void setValue(int index, Object v) { |
public final void setValue(int index, Object v) { |
this.values.set(index, v); |
} |
public Boolean isFillWidth() { |
public final Boolean isFillWidth() { |
return this.fillWidth; |
} |
public void setFillWidth(final Boolean fillWidth) { |
public final void setFillWidth(final Boolean fillWidth) { |
this.fillWidth = fillWidth; |
} |
public Boolean isToggleable() { |
public final Boolean isToggleable() { |
return this.toggleable; |
} |
public void setToggleable(final Boolean toggleable) { |
public final void setToggleable(final Boolean toggleable) { |
this.toggleable = toggleable; |
} |
public Boolean isVisible() { |
public final Boolean isVisible() { |
return this.visible; |
} |
public void setVisible(final Boolean visible) { |
public final void setVisible(final Boolean visible) { |
this.visible = visible; |
} |
@Override |
public void writeExternal(ObjectOutput out) throws IOException { |
out.writeLong(this.id); |
out.writeObject(this.id); |
out.writeUTF(this.extendId); |
out.writeObject(this.values); |
out.writeBoolean(this.fillWidth); |
127,9 → 123,9 |
@Override |
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
this.id = in.readLong(); |
this.id = (Number) in.readObject(); |
this.extendId = in.readUTF(); |
this.values = (List<Object>) in.readObject(); |
this.values = CollectionUtils.castList((List<?>) in.readObject(), Object.class); |
this.fillWidth = in.readBoolean(); |
this.toggleable = in.readBoolean(); |
this.visible = in.readBoolean(); |
141,32 → 137,32 |
result.put("class", "Row"); |
result.put("id", this.id); |
if(this.extendId != null) { |
if (this.extendId != null) { |
result.put("extend-id", this.extendId); |
} |
if(!this.values.isEmpty()) { |
if (!this.values.isEmpty()) { |
result.put("values", JSONConverter.getJSON(this.values)); |
} |
if(this.fillWidth) { |
if (this.fillWidth) { |
result.put("fill-width", true); |
} |
if(this.toggleable) { |
if (this.toggleable) { |
result.put("toggleable", true); |
} |
if(!this.visible) { |
if (!this.visible) { |
result.put("visible", false); |
} |
return result; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
this.id = (Long) JSONConverter.getParameterFromJSON(json, "id", Long.class); |
this.extendId = (String) JSONConverter.getParameterFromJSON(json, "extend-id", String.class); |
this.fillWidth = (Boolean) JSONConverter.getParameterFromJSON(json, "fill-width", Boolean.class, false); |
this.toggleable = (Boolean) JSONConverter.getParameterFromJSON(json, "toggleable", Boolean.class, false); |
this.visible = (Boolean) JSONConverter.getParameterFromJSON(json, "visible", Boolean.class, true); |
this.id = JSONConverter.getParameterFromJSON(json, "id", Number.class); |
this.extendId = JSONConverter.getParameterFromJSON(json, "extend-id", String.class); |
this.fillWidth = JSONConverter.getParameterFromJSON(json, "fill-width", Boolean.class, false); |
this.toggleable = JSONConverter.getParameterFromJSON(json, "toggleable", Boolean.class, false); |
this.visible = JSONConverter.getParameterFromJSON(json, "visible", Boolean.class, true); |
final JSONArray jsonValues = (JSONArray) JSONConverter.getParameterFromJSON(json, "values", JSONArray.class); |
if (jsonValues != null) { |
176,27 → 172,17 |
Object objValue = jsonValues.get(i); |
if (objValue instanceof JSONObject) { |
final JSONObject jsonValue = (JSONObject) objValue; |
final String valueClassName = (String) JSONConverter.getParameterFromJSON(jsonValue, "class", String.class); |
if (valueClassName == null){ |
throw new IllegalArgumentException("null value store in ghost"); |
} |
if(valueClassName.equals(StringWithId.class.getSimpleName())) { |
objValue = new StringWithId(jsonValue); |
} else if (valueClassName.equals(LightUIElement.class.getSimpleName())) { |
objValue = JSONToLightUIConvertorManager.getInstance().createUIElementFromJSON(jsonValue); |
} else { |
throw new IllegalArgumentException("invalid value for 'values', StringWithId or LightUIElement expected"); |
} |
objValue = JSONToLightUIConvertorManager.getInstance().createUIElementFromJSON(jsonValue); |
} else { |
if(objValue instanceof String) { |
if (objValue instanceof String) { |
objValue = JSONConverter.getObjectFromJSON(objValue, String.class); |
} else if(objValue instanceof Integer) { |
} else if (objValue instanceof Integer) { |
objValue = JSONConverter.getObjectFromJSON(objValue, Integer.class); |
} else if(objValue instanceof Long) { |
} else if (objValue instanceof Long) { |
objValue = JSONConverter.getObjectFromJSON(objValue, Long.class); |
} else if(objValue instanceof Boolean) { |
} else if (objValue instanceof Boolean) { |
objValue = JSONConverter.getObjectFromJSON(objValue, Boolean.class); |
} else if(objValue != null) { |
} else if (objValue != null) { |
throw new IllegalArgumentException("unknow type: " + objValue.getClass().getName()); |
} |
} |
204,9 → 190,9 |
} |
} |
} |
@Override |
public String toString() { |
return "Row id: " + this.id + " values: " + this.values; |
return "Row index: " + this.id + " values: " + this.values; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIComboBoxElement.java |
---|
15,6 → 15,7 |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.utils.io.Transferable; |
import net.minidev.json.JSONObject; |
public class LightUIComboBoxElement implements Transferable { |
35,11 → 36,29 |
public LightUIComboBoxElement(final int id) { |
this.id = id; |
} |
public LightUIComboBoxElement(final int id, final String value1) { |
this.id = id; |
this.value1 = value1; |
} |
public LightUIComboBoxElement(final int id, final String value1, final String value2) { |
this.id = id; |
this.value1 = value1; |
this.value2 = value2; |
} |
public LightUIComboBoxElement(final LightUIComboBoxElement comboElement) { |
this.id = comboElement.id; |
this.value1 = comboElement.value1; |
this.value2 = comboElement.value2; |
this.icon = comboElement.icon; |
} |
public int getId() { |
return this.id; |
} |
public String getValue1() { |
return this.value1; |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ColumnSpec.java |
---|
15,7 → 15,6 |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.utils.io.Transferable; |
import org.openconcerto.utils.ui.StringWithId; |
import java.io.Externalizable; |
import java.io.IOException; |
27,17 → 26,33 |
import net.minidev.json.JSONObject; |
public class ColumnSpec implements Externalizable, Transferable { |
private static final String DEFAULT_VALUE = "default-value"; |
private static final String EDITORS = "editors"; |
private static final String VALUE_CLASS = "value-class"; |
private static final String ID = "id"; |
private static final String COLUMN_NAME = "column-name"; |
private static final String WIDTH = "width"; |
private static final String MAX_WIDTH = "max-width"; |
private static final String MIN_WIDTH = "min-width"; |
private static final String EDITABLE = "editable"; |
private static final String HORIZONTAL_ALIGNMENT = "h-align"; |
// Must stay immutable |
private String id; |
private String columnName; |
private String id; |
private Class<?> valueClass; |
private String columnName; |
// Default value (to add a new line) |
private Object defaultValue; |
private int width; |
private int maxWidth; |
private int minWidth; |
private Integer horizontalAlignment = null; |
private double width; |
private double maxWidth; |
private double minWidth; |
private boolean editable; |
private LightUIElement editors; |
public ColumnSpec() { |
48,12 → 63,12 |
this.fromJSON(json); |
} |
public ColumnSpec(final String id, final Class<?> valueClass, final String columnName, final Object defaultValue, final int width, final boolean editable, final LightUIElement editors) { |
public ColumnSpec(final String id, final Class<?> valueClass, final String columnName, final Object defaultValue, final double width, final boolean editable, final LightUIElement editors) { |
this.init(id, valueClass, columnName, defaultValue, editable, editors); |
this.width = width; |
final int minWidth = width - 200; |
final int maxWidth = width + 200; |
final double minWidth = width - 200; |
final double maxWidth = width + 200; |
this.minWidth = (minWidth < 10) ? 10 : minWidth; |
this.maxWidth = maxWidth; |
73,7 → 88,7 |
this.editors = editors; |
} |
public void setPrefs(final int width, final int maxWidth, final int minWidth) { |
public void setPrefs(final double width, final double maxWidth, final double minWidth) { |
this.width = width; |
this.maxWidth = maxWidth; |
this.minWidth = minWidth; |
95,6 → 110,14 |
this.valueClass = valueClass; |
} |
public int getHorizontalAlignment() { |
return this.horizontalAlignment; |
} |
public void setHorizontalAlignment(final int horizontalAlignment) { |
this.horizontalAlignment = horizontalAlignment; |
} |
public String getColumnName() { |
return this.columnName; |
} |
111,27 → 134,27 |
this.defaultValue = defaultValue; |
} |
public int getMaxWidth() { |
public double getMaxWidth() { |
return this.maxWidth; |
} |
public void setMaxWidth(final int maxWidth) { |
public void setMaxWidth(final double maxWidth) { |
this.maxWidth = maxWidth; |
} |
public int getMinWidth() { |
public double getMinWidth() { |
return this.minWidth; |
} |
public void setMinWidth(final int minWidth) { |
public void setMinWidth(final double minWidth) { |
this.minWidth = minWidth; |
} |
public int getWidth() { |
public double getWidth() { |
return this.width; |
} |
public void setWidth(int width) { |
public void setWidth(double width) { |
this.width = width; |
} |
160,10 → 183,10 |
public Element createXmlColumnPref() { |
final Element columnElement = new Element("column"); |
columnElement.setAttribute("id", this.getId()); |
columnElement.setAttribute("max-width", String.valueOf(this.getMaxWidth())); |
columnElement.setAttribute("min-width", String.valueOf(this.getMinWidth())); |
columnElement.setAttribute("width", String.valueOf(this.getWidth())); |
columnElement.setAttribute(ID, this.getId()); |
columnElement.setAttribute(MAX_WIDTH, String.valueOf(this.getMaxWidth())); |
columnElement.setAttribute(MIN_WIDTH, String.valueOf(this.getMinWidth())); |
columnElement.setAttribute(WIDTH, String.valueOf(this.getWidth())); |
return columnElement; |
} |
171,13 → 194,14 |
public void writeExternal(ObjectOutput out) throws IOException { |
out.writeUTF(this.id); |
out.writeUTF(this.columnName); |
out.writeInt(this.width); |
out.writeInt(this.maxWidth); |
out.writeInt(this.minWidth); |
out.writeDouble(this.width); |
out.writeDouble(this.maxWidth); |
out.writeDouble(this.minWidth); |
out.writeObject(this.defaultValue); |
out.writeBoolean(this.editable); |
out.writeObject(this.editors); |
out.writeObject(this.valueClass); |
out.writeInt(this.horizontalAlignment); |
} |
@Override |
184,13 → 208,14 |
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
this.id = in.readUTF(); |
this.columnName = in.readUTF(); |
this.width = in.readInt(); |
this.maxWidth = in.readInt(); |
this.minWidth = in.readInt(); |
this.width = in.readDouble(); |
this.maxWidth = in.readDouble(); |
this.minWidth = in.readDouble(); |
this.defaultValue = in.readObject(); |
this.editable = in.readBoolean(); |
this.editors = (LightUIElement) in.readObject(); |
this.valueClass = (Class<?>) in.readObject(); |
this.horizontalAlignment = in.readInt(); |
} |
@Override |
197,45 → 222,60 |
public JSONObject toJSON() { |
final JSONObject result = new JSONObject(); |
result.put("class", "ColumnSpec"); |
result.put("id", this.id); |
result.put("column-name", this.columnName); |
result.put("width", this.width); |
result.put("max-width", this.maxWidth); |
result.put("min-width", this.minWidth); |
result.put(ID, this.id); |
result.put(COLUMN_NAME, this.columnName); |
result.put(WIDTH, this.width); |
result.put(MAX_WIDTH, this.maxWidth); |
result.put(MIN_WIDTH, this.minWidth); |
if (this.defaultValue != null) { |
result.put("default-value", JSONConverter.getJSON(this.defaultValue)); |
result.put(DEFAULT_VALUE, JSONConverter.getJSON(this.defaultValue)); |
} |
if (this.editable) { |
result.put("editable", true); |
result.put(EDITABLE, true); |
} |
if (this.editors != null) { |
result.put("editors", JSONConverter.getJSON(this.editors)); |
result.put(EDITORS, JSONConverter.getJSON(this.editors)); |
} |
result.put("value-class", JSONConverter.getJSON(this.valueClass)); |
result.put(VALUE_CLASS, JSONConverter.getJSON(this.valueClass)); |
if (this.horizontalAlignment != null) { |
result.put(HORIZONTAL_ALIGNMENT, this.horizontalAlignment); |
} |
return result; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
this.id = (String) JSONConverter.getParameterFromJSON(json, "id", String.class); |
this.columnName = (String) JSONConverter.getParameterFromJSON(json, "column-name", String.class); |
this.width = (Integer) JSONConverter.getParameterFromJSON(json, "width", Integer.class); |
this.maxWidth = (Integer) JSONConverter.getParameterFromJSON(json, "max-width", Integer.class); |
this.minWidth = (Integer) JSONConverter.getParameterFromJSON(json, "min-width", Integer.class); |
this.editable = (Boolean) JSONConverter.getParameterFromJSON(json, "editable", Boolean.class, Boolean.FALSE); |
this.id = JSONConverter.getParameterFromJSON(json, ID, String.class); |
this.columnName = JSONConverter.getParameterFromJSON(json, COLUMN_NAME, String.class); |
final JSONObject jsonDefaultValue = (JSONObject) JSONConverter.getParameterFromJSON(json, "default-value", JSONObject.class); |
if (jsonDefaultValue != null) { |
final String defaultValueClassName = (String) JSONConverter.getParameterFromJSON(jsonDefaultValue, "class", String.class); |
if (defaultValueClassName.equals(StringWithId.class.getSimpleName())) { |
this.defaultValue = new StringWithId(jsonDefaultValue); |
} |
/** JavaScript convert Double to Long, this will fix that. **/ |
final Number numWidth = JSONConverter.getParameterFromJSON(json, WIDTH, Number.class); |
final Number numMaxWidth = JSONConverter.getParameterFromJSON(json, MAX_WIDTH, Number.class); |
final Number numMinWidth = JSONConverter.getParameterFromJSON(json, MIN_WIDTH, Number.class); |
if (numWidth != null) { |
this.width = numWidth.doubleValue(); |
} |
final JSONObject jsonEditors = (JSONObject) JSONConverter.getParameterFromJSON(json, "editors", JSONObject.class); |
if (numMaxWidth != null) { |
this.maxWidth = numMaxWidth.doubleValue(); |
} |
if (numMinWidth != null) { |
this.minWidth = numMinWidth.doubleValue(); |
} |
/************************************************************/ |
this.editable = JSONConverter.getParameterFromJSON(json, EDITABLE, Boolean.class, Boolean.FALSE); |
this.horizontalAlignment = JSONConverter.getParameterFromJSON(json, HORIZONTAL_ALIGNMENT, Integer.class); |
final JSONObject jsonDefaultValue = JSONConverter.getParameterFromJSON(json, DEFAULT_VALUE, JSONObject.class); |
// TODO: implement default value |
final JSONObject jsonEditors = JSONConverter.getParameterFromJSON(json, EDITORS, JSONObject.class); |
if (jsonEditors != null) { |
this.editors = JSONToLightUIConvertorManager.getInstance().createUIElementFromJSON(jsonEditors); |
} |
final String sValueClass = (String) JSONConverter.getParameterFromJSON(json, "value-class", String.class); |
final String sValueClass = JSONConverter.getParameterFromJSON(json, VALUE_CLASS, String.class); |
if (sValueClass != null) { |
try { |
this.valueClass = Class.forName(sValueClass); |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIFileUpload.java |
---|
Nouveau fichier |
0,0 → 1,90 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUIFileUpload extends LightUserControl { |
private static final String SEND_FILE_URL_JSON_KEY = "send-file-url"; |
private String sendFileUrl; |
public LightUIFileUpload(final JSONObject json) { |
super(json); |
} |
public LightUIFileUpload(final LightUIFileUpload file) { |
super(file); |
} |
public LightUIFileUpload(final String id, final String sendFileUrl) { |
super(id); |
this.setType(LightUIElement.TYPE_FILE_UPLOAD); |
this.sendFileUrl = sendFileUrl; |
} |
@Override |
public JSONToLightUIConvertor getConvertor() { |
return new JSONToLightUIConvertor() { |
@Override |
public LightUIElement convert(final JSONObject json) { |
return new LightUIFileUpload(json); |
} |
}; |
} |
@Override |
public LightUIElement clone() { |
return new LightUIFileUpload(this); |
} |
@Override |
protected void copy(LightUIElement element) { |
super.copy(element); |
if (!(element instanceof LightUIFileUpload)) { |
throw new InvalidClassException(this.getClassName(), element.getClassName(), element.getId()); |
} |
final LightUIFileUpload files = (LightUIFileUpload) element; |
this.sendFileUrl = files.sendFileUrl; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.sendFileUrl = JSONConverter.getParameterFromJSON(json, SEND_FILE_URL_JSON_KEY, String.class); |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put(SEND_FILE_URL_JSON_KEY, this.sendFileUrl); |
return json; |
} |
@Override |
public void _setValueFromContext(final Object value) { |
this.setValue((String) value); |
} |
@Override |
public Object getValueForContext() { |
return this.getValue(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUserControlContainer.java |
---|
Nouveau fichier |
0,0 → 1,44 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import net.minidev.json.JSONObject; |
public abstract class LightUserControlContainer extends LightUIContainer { |
public LightUserControlContainer(final String id) { |
super(id); |
} |
public LightUserControlContainer(final JSONObject json) { |
super(json); |
} |
public LightUserControlContainer(final LightUserControlContainer userControlContainer) { |
super(userControlContainer); |
} |
public void setValueFromContext(final Object value) { |
if (this.isEnabled()) { |
this._setValueFromContext(value); |
} |
} |
/** |
* Set value for all elements send by client with buttons TYPE_BUTTON_WITH_SELECTION_CONTEXT and |
* TYPE_BUTTON_WITH_CONTEXT |
* |
* @param value to set for element |
*/ |
protected abstract void _setValueFromContext(final Object value); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TreeSpec.java |
---|
23,7 → 23,7 |
} |
public String getId() { |
return id; |
return this.id; |
} |
public void setId(String id) { |
31,7 → 31,7 |
} |
public List<TreeItem> getChildren() { |
return children; |
return this.children; |
} |
public void setChildren(List<TreeItem> children) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUILine.java |
---|
68,7 → 68,7 |
this.gridAlignment = gridAlignment; |
} |
public Integer getHeight() { |
public Integer getTotalHeight() { |
Integer h = 0; |
final int size = this.getChildrenCount(); |
for (int i = 0; i < size; i++) { |
77,7 → 77,7 |
return h; |
} |
public Integer getWidth() { |
public Integer getTotalGridWidth() { |
Integer w = 0; |
final int size = this.getChildrenCount(); |
for (int i = 0; i < size; i++) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITable.java |
---|
13,6 → 13,7 |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.NumberUtils; |
import org.openconcerto.utils.io.JSONConverter; |
import java.awt.event.ActionEvent; |
20,15 → 21,29 |
import java.util.ArrayList; |
import java.util.List; |
import javax.xml.parsers.ParserConfigurationException; |
import org.jdom2.Document; |
import org.jdom2.Element; |
import net.minidev.json.JSONArray; |
import net.minidev.json.JSONObject; |
public class LightUITable extends LightUIElement implements IUserControlContainer { |
public class LightUITable extends LightUserControlContainer { |
public static final int DEFAULT_LINE_HEIGHT = 40; |
private static final String LINE_PER_ROW = "line-per-row"; |
private static final String TABLE_SPEC = "table-spec"; |
private static final String ALLOW_SELECTION = "allow-selection"; |
private static final String ALLOW_MULTI_SELECTION = "allow-multi-selection"; |
private static final String DYNAMIC_LOAD = "dynamic-load"; |
private static final String AUTO_SELECT_FIRST_LINE = "auto-select-first-line"; |
private Boolean dynamicLoad = false; |
private Boolean verticallyScrollable = false; |
private Boolean allowSelection = false; |
private Boolean allowMultiSelection = false; |
private Boolean autoSelectFirstLine = true; |
private TableSpec tableSpec = null; |
private String elementCode = null; |
private List<ActionListener> selectionListeners = new ArrayList<ActionListener>(); |
35,6 → 50,8 |
// Nombre de ligne à afficher par Row |
private int linePerRow = 1; |
private int lineHeight = DEFAULT_LINE_HEIGHT; |
// Init from json constructor |
public LightUITable(final JSONObject json) { |
super(json); |
43,9 → 60,7 |
// Clone constructor |
public LightUITable(final LightUITable tableElement) { |
super(tableElement); |
this.verticallyScrollable = tableElement.verticallyScrollable; |
this.tableSpec = tableElement.tableSpec; |
this.elementCode = tableElement.elementCode; |
this.allowSelection = tableElement.allowSelection; |
} |
55,82 → 70,187 |
this.setWeightX(1); |
this.setFillWidth(true); |
} |
public int getIndexfromRowID(int rowID) { |
final TableContent content = this.getTableSpec().getContent(); |
final RowSelectionSpec selection = new RowSelectionSpec(this.getId()); |
final ColumnsSpec columnsSpec = new ColumnsSpec(this.getId(), new ArrayList<ColumnSpec>(), new ArrayList<String>(), new ArrayList<String>()); |
final TableSpec tableSpec = new TableSpec(this.getId(), selection, columnsSpec); |
tableSpec.setContent(new TableContent(this.getId())); |
for (int i = 0; i < content.getRows().size(); i++) { |
Row r = content.getRows().get(i); |
if (r.getId() == rowID) { |
return i; |
} |
} |
return -1; |
this.setTableSpec(tableSpec); |
} |
@Override |
public void setId(final String id) { |
super.setId(id); |
this.tableSpec.setId(id); |
this.tableSpec.getSelection().setTableId(id); |
} |
public String getElementCode() { |
return this.elementCode; |
} |
if (this.tableSpec != null) { |
this.tableSpec.setId(id); |
public void setElementCode(final String elementCode) { |
this.elementCode = elementCode; |
if (this.tableSpec.getSelection() != null) { |
this.tableSpec.getSelection().setTableId(id); |
} |
if (this.tableSpec.getContent() != null) { |
this.tableSpec.getContent().setTableId(id); |
} |
} |
} |
public void setLinePerRow(int linePerRow) { |
public final void setLinePerRow(int linePerRow) { |
this.linePerRow = linePerRow; |
} |
public int getLinePerRow() { |
public final int getLinePerRow() { |
return this.linePerRow; |
} |
public TableSpec getTableSpec() { |
public final void setLineHeight(int lineHeight) { |
this.lineHeight = lineHeight; |
} |
public final int getLineHeight() { |
return this.lineHeight; |
} |
public final TableSpec getTableSpec() { |
return this.tableSpec; |
} |
public void setTableSpec(final TableSpec tableSpec) { |
public final void setTableSpec(final TableSpec tableSpec) { |
this.tableSpec = tableSpec; |
} |
public Boolean isAllowSelection() { |
public final Boolean isAllowSelection() { |
return this.allowSelection; |
} |
public void setAllowSelection(final boolean allowSelection) { |
public final void setAllowSelection(final boolean allowSelection) { |
this.allowSelection = allowSelection; |
} |
public Boolean isDynamicLoad() { |
public final Boolean isAllowMultiSelection() { |
return this.allowMultiSelection; |
} |
public final void setAllowMultiSelection(final boolean allowMultiSelection) { |
this.allowMultiSelection = allowMultiSelection; |
} |
public final Boolean isDynamicLoad() { |
return this.dynamicLoad; |
} |
public void setDynamicLoad(final boolean dynamicLoad) { |
public final void setDynamicLoad(final boolean dynamicLoad) { |
this.dynamicLoad = dynamicLoad; |
} |
public Boolean isVerticallyScrollable() { |
return this.verticallyScrollable; |
public final Boolean isAutoSelectFirstLine() { |
return this.autoSelectFirstLine; |
} |
public void setVerticallyScrollable(final Boolean verticallyScrollable) { |
this.verticallyScrollable = verticallyScrollable; |
public final void setAutoSelectFirstLine(final boolean autoSelectFirstLine) { |
this.autoSelectFirstLine = autoSelectFirstLine; |
} |
public boolean replaceChild(final LightUIElement pChild) { |
final List<Row> tableRows = this.getTableSpec().getContent().getRows(); |
final int tableRowsCount = tableRows.size(); |
public final Row removeRow(final int index) { |
return this.tableSpec.getContent().removeRow(index); |
} |
public final boolean removeRow(final Row row) { |
final TableContent content = this.getTableSpec().getContent(); |
return content.removeRow(row); |
} |
public final boolean hasRow() { |
return (this.tableSpec != null && this.tableSpec.getContent() != null && this.tableSpec.getContent().getRowsCount() > 0); |
} |
public final Row getRow(final int index) { |
return this.getTableSpec().getContent().getRow(index); |
} |
public Row getRowById(final Number rowId) { |
final int size = this.getTableSpec().getContent().getRowsCount(); |
for (int i = 0; i < size; i++) { |
final Row row = this.getRow(i); |
if (NumberUtils.areNumericallyEqual(row.getId(), rowId)) { |
return row; |
} else { |
System.err.println("LightUITable.getSelectedRows() - Null selectedRow"); |
} |
} |
return null; |
} |
public final Row setRow(final int index, final Row row) { |
return this.getTableSpec().getContent().setRow(index, row); |
} |
public final boolean addRow(final Row row) { |
return this.getTableSpec().getContent().addRow(row); |
} |
public final int getRowsCount() { |
return this.getTableSpec().getContent().getRowsCount(); |
} |
public final void clearRows() { |
this.getTableSpec().getContent().clearRows(); |
} |
/** |
* Get Ids of SQLRowAccessor store in selected rows |
* |
* @return The list of selected DB Ids |
*/ |
public final List<Number> getSelectedIds() { |
return this.getTableSpec().getSelection().getIds(); |
} |
public final Number getFirstSelectedId() { |
final List<Number> selectedIds = this.getTableSpec().getSelection().getIds(); |
if (selectedIds.isEmpty()) { |
return null; |
} else { |
return selectedIds.get(0); |
} |
} |
public final void setSelectedIds(final List<Number> selectedIds, final boolean fire) { |
this.getTableSpec().getSelection().setIds(selectedIds); |
if (fire) { |
this.fireSelectionChange(); |
} |
} |
public final void clearSelection(final boolean fire) { |
this.getTableSpec().getSelection().getIds().clear(); |
if (fire) { |
this.fireSelectionChange(); |
} |
} |
public final List<Row> getSelectedRows() { |
final List<Row> selectedRows = new ArrayList<Row>(); |
if (this.getTableSpec().getSelection() != null) { |
final List<Number> selectedIds = this.getSelectedIds(); |
for (final Number selectedId : selectedIds) { |
final Row selectedRow = this.getRowById(selectedId); |
if (selectedRow != null) { |
selectedRows.add(selectedRow); |
} |
} |
} |
return selectedRows; |
} |
public final boolean replaceChild(final LightUIElement pChild) { |
pChild.setReadOnly(this.isReadOnly()); |
for (int i = 0; i < tableRowsCount; i++) { |
final Row tableRow = tableRows.get(i); |
for (int i = 0; i < this.getRowsCount(); i++) { |
final Row tableRow = this.getTableSpec().getContent().getRow(i); |
final List<Object> tableRowValues = tableRow.getValues(); |
final int tableRowValuesCount = tableRowValues.size(); |
160,90 → 280,179 |
return false; |
} |
public LightUIElement findElement(final String searchParam, final boolean byUUID) { |
public final LightUIElement findElement(final String searchParam, final boolean byUUID) { |
return this.findElement(searchParam, byUUID, LightUIElement.class); |
} |
public <T extends LightUIElement> T findElement(final String searchParam, final boolean byUUID, final Class<T> objectClass) { |
if (this.tableSpec != null) { |
final TableContent content = this.tableSpec.getContent(); |
if (content != null) { |
final List<Row> listRows = content.getRows(); |
if (listRows != null) { |
for (final Row row : listRows) { |
final List<Object> rowValues = row.getValues(); |
for (final Object value : rowValues) { |
if (value instanceof LightUIContainer) { |
final LightUIContainer panel = (LightUIContainer) value; |
final T element = panel.findChild(searchParam, byUUID, objectClass); |
if (element != null) { |
return element; |
public final <T extends LightUIElement> T findElement(final String searchParam, final boolean byUUID, final Class<T> objectClass) { |
if (this.hasRow()) { |
for (int i = 0; i < this.getRowsCount(); i++) { |
final Row row = this.getRow(i); |
final List<Object> rowValues = row.getValues(); |
for (final Object value : rowValues) { |
if (value instanceof LightUIContainer) { |
final LightUIContainer panel = (LightUIContainer) value; |
final T element = panel.findChild(searchParam, byUUID, objectClass); |
if (element != null) { |
return element; |
} |
} else if (value instanceof LightUIElement) { |
final LightUIElement element = (LightUIElement) value; |
if (byUUID) { |
if (element.getUUID().equals(searchParam)) { |
if (objectClass.isAssignableFrom(element.getClass())) { |
return objectClass.cast(element); |
} else { |
throw new IllegalArgumentException( |
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId()); |
} |
} else if (value instanceof LightUIElement) { |
final LightUIElement element = (LightUIElement) value; |
if (byUUID) { |
if (element.getUUID().equals(searchParam)) { |
if (objectClass.isAssignableFrom(element.getClass())) { |
return (T) element; |
} else { |
throw new IllegalArgumentException("Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() |
+ " element ID: " + element.getId()); |
} |
} |
} |
} else { |
if (element.getId().equals(searchParam)) { |
if (objectClass.isAssignableFrom(element.getClass())) { |
return objectClass.cast(element); |
} else { |
if (element.getId().equals(searchParam)) { |
if (objectClass.isAssignableFrom(element.getClass())) { |
return (T) element; |
} else { |
throw new IllegalArgumentException("Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() |
+ " element ID: " + element.getId()); |
} |
} |
throw new IllegalArgumentException( |
"Element found at is not an instance of " + objectClass.getName() + ", element class: " + element.getClass().getName() + " element ID: " + element.getId()); |
} |
} |
} |
if (element instanceof LightUITable) { |
final T resultElement = ((LightUITable) element).findElement(searchParam, byUUID, objectClass); |
if (resultElement != null) { |
return resultElement; |
} |
} |
if (element instanceof LightUITable) { |
final T resultElement = ((LightUITable) element).findElement(searchParam, byUUID, objectClass); |
if (resultElement != null) { |
return resultElement; |
} |
} |
} |
} else { |
System.out.println("LightUITable.getElementById() - No rows for table: " + this.getId()); |
} |
} else { |
System.out.println("LightUITable.getElementById() - Null TableContent for table: " + this.getId()); |
} |
} else { |
System.out.println("LightUITable.getElementById() - Null TableSpec for table: " + this.getId()); |
System.out.println("LightUITable.getElementById() - No rows for table: " + this.getId()); |
} |
return null; |
} |
public void addSelectionListener(final ActionListener selectionListener) { |
public <T extends LightUIElement> List<T> findChildren(final Class<T> expectedClass, final boolean recursively) { |
final List<T> result = new ArrayList<T>(); |
if (this.hasRow()) { |
final int size = this.getRowsCount(); |
for (int i = 0; i < size; i++) { |
final Row row = this.getRow(i); |
final List<Object> rowValues = row.getValues(); |
for (final Object value : rowValues) { |
if (recursively) { |
if (value instanceof LightUIContainer) { |
result.addAll(((LightUIContainer) value).findChildren(expectedClass, recursively)); |
} else if (value instanceof LightUITable) { |
result.addAll(((LightUITable) value).findChildren(expectedClass, recursively)); |
} |
} |
if (expectedClass.isAssignableFrom(value.getClass())) { |
result.add(expectedClass.cast(value)); |
} |
} |
} |
} else { |
System.out.println("LightUITable.getElementById() - No rows for table: " + this.getId()); |
} |
return result; |
} |
public final void addSelectionListener(final ActionListener selectionListener) { |
this.selectionListeners.add(selectionListener); |
} |
public void removeSelectionListeners() { |
public final void removeSelectionListeners() { |
this.selectionListeners.clear(); |
} |
public void fireSelectionChange() { |
public final void fireSelectionChange() { |
for (final ActionListener listener : this.selectionListeners) { |
listener.actionPerformed(new ActionEvent(this, 1, "selection")); |
} |
} |
// TODO: garder l'ordre des colonnes invisibles |
/** |
* Create columns preferences with the current ColumnsSpec |
* |
* @return XML document with columns preferences |
*/ |
public final Document createXmlPreferences(final Document userPrefs, final ColumnsSpec columnsSpec) throws ParserConfigurationException { |
final Element rootElement = new Element("list"); |
final Document xmlConf = new Document(); |
final int columnSpecCount = columnsSpec.getColumnCount(); |
final List<String> visibleIds = new ArrayList<String>(); |
for (int i = 0; i < columnSpecCount; i++) { |
final ColumnSpec columnSpec = columnsSpec.getColumn(i); |
final Element xmlColumn = this.createXmlColumn(columnSpec.getId(), columnSpec.getMaxWidth(), columnSpec.getMinWidth(), columnSpec.getWidth()); |
rootElement.addContent(xmlColumn); |
visibleIds.add(columnSpec.getId()); |
} |
final Element rootUserPrefs = userPrefs.getRootElement(); |
final List<Element> xmlColumns = rootUserPrefs.getChildren(); |
final int columnsSize = xmlColumns.size(); |
for (int i = 0; i < columnsSize; i++) { |
final Element xmlColumn = xmlColumns.get(i); |
final String columnId = xmlColumn.getAttribute("id").getValue(); |
if (!visibleIds.contains(columnId)) { |
final int maxWidth = Integer.parseInt(xmlColumn.getAttribute("max-width").getValue()); |
final int minWidth = Integer.parseInt(xmlColumn.getAttribute("min-width").getValue()); |
final int width = Integer.parseInt(xmlColumn.getAttribute("width").getValue()); |
final Element newXmlColumn = this.createXmlColumn(columnId, maxWidth, minWidth, width); |
rootElement.addContent(newXmlColumn); |
} |
} |
xmlConf.setRootElement(rootElement); |
return xmlConf; |
} |
/** |
* Create default columns preferences from the SQLTableModelLinesSourceOnline |
* |
* @return XML document with columns preferences |
*/ |
public Document createDefaultXmlPreferences() { |
final Element rootElement = new Element("list"); |
if (this.getTableSpec() != null && this.getTableSpec().getColumns() != null) { |
final int sqlColumnsCount = this.getTableSpec().getColumns().getColumnCount(); |
for (int i = 0; i < sqlColumnsCount; i++) { |
final ColumnSpec column = this.getTableSpec().getColumns().getColumn(i); |
final String columnId = column.getId(); |
final Element columnElement = this.createXmlColumn(columnId, column.getMaxWidth(), column.getMinWidth(), column.getWidth()); |
rootElement.addContent(columnElement); |
} |
} |
final Document xmlConf = new Document(rootElement); |
return xmlConf; |
} |
protected final Element createXmlColumn(final String columnId, final double maxWidth, final double minWidth, final double width) { |
final Element columnElement = new Element("column"); |
columnElement.setAttribute("id", columnId); |
columnElement.setAttribute("max-width", String.valueOf(maxWidth)); |
columnElement.setAttribute("min-width", String.valueOf(minWidth)); |
columnElement.setAttribute("width", String.valueOf(width)); |
return columnElement; |
} |
@Override |
public void setReadOnly(final boolean readOnly) { |
super.setReadOnly(readOnly); |
final List<Row> rows = this.tableSpec.getContent().getRows(); |
if (rows != null) { |
final int rowCount = rows.size(); |
for (int i = 0; i < rowCount; i++) { |
final Row row = rows.get(i); |
if (this.hasRow()) { |
final int size = this.getRowsCount(); |
for (int i = 0; i < size; i++) { |
final Row row = this.getRow(i); |
final List<Object> values = row.getValues(); |
for (final Object value : values) { |
if (value != null && value instanceof LightUIElement) { |
265,7 → 474,7 |
} |
@Override |
public void setValueFromContext(final Object value) { |
public void _setValueFromContext(final Object value) { |
if (value != null) { |
final JSONArray jsonContext = (JSONArray) JSONConverter.getObjectFromJSON(value, JSONArray.class); |
final ColumnsSpec columnsSpec = this.getTableSpec().getColumns(); |
280,45 → 489,49 |
} |
} |
final TableContent tableContent = this.getTableSpec().getContent(); |
if (tableContent != null) { |
final List<Row> rows = tableContent.getRows(); |
for (int i = 0; i < rows.size(); i++) { |
final Row row = rows.get(i); |
final JSONObject jsonLineContext = (JSONObject) JSONConverter.getObjectFromJSON(jsonContext.get(i), JSONObject.class); |
final Long rowId = (Long) JSONConverter.getParameterFromJSON(jsonLineContext, "row.id", Long.class); |
final String rowExtendId = (String) JSONConverter.getParameterFromJSON(jsonLineContext, "row.extend.id", String.class); |
if (rowId == row.getId() && (row.getExtendId() == null || (row.getExtendId() != null && rowExtendId.equals(row.getExtendId())))) { |
if (row.isFillWidth()) { |
if (!row.getValues().isEmpty() && row.getValues().get(0) instanceof IUserControl) { |
final LightUIElement element = (LightUIElement) row.getValues().get(0); |
if (element instanceof IUserControl) { |
if (jsonLineContext.containsKey(element.getUUID())) { |
((IUserControl) element).setValueFromContext(jsonLineContext.get(element.getUUID())); |
if (this.hasRow()) { |
final int size = this.getRowsCount(); |
if (jsonContext.size() != size) { |
System.err.println("LightUITable.setValueFromContext() - Incorrect line count in JSON"); |
} else { |
for (int i = 0; i < size; i++) { |
final Row row = this.getRow(i); |
final JSONObject jsonLineContext = (JSONObject) JSONConverter.getObjectFromJSON(jsonContext.get(i), JSONObject.class); |
final Number rowId = JSONConverter.getParameterFromJSON(jsonLineContext, "row.id", Number.class); |
final String rowExtendId = (String) JSONConverter.getParameterFromJSON(jsonLineContext, "row.extend.id", String.class); |
if (NumberUtils.areNumericallyEqual(rowId, row.getId()) && (row.getExtendId() == null || (row.getExtendId() != null && rowExtendId.equals(row.getExtendId())))) { |
if (row.isFillWidth()) { |
if (!row.getValues().isEmpty() && row.getValues().get(0) instanceof LightUserControl) { |
final LightUIElement element = (LightUIElement) row.getValues().get(0); |
if (element instanceof LightUserControl) { |
if (jsonLineContext.containsKey(element.getUUID())) { |
((LightUserControl) element)._setValueFromContext(jsonLineContext.get(element.getUUID())); |
} else { |
System.out.println("LightUITable.setValueFromContext() - Unable to find element : id - " + element.getId() + " uuid - " + element.getUUID()); |
System.out.println("LightUITable.setValueFromContext() - In JSON : " + jsonLineContext.toJSONString()); |
} |
} |
} |
} else { |
for (int k = 0; k < editorsIndex.size(); k++) { |
final Object objEditor = row.getValues().get(editorsIndex.get(k)); |
if (!(objEditor instanceof LightUserControl)) { |
throw new IllegalArgumentException("Impossible to find editor for row: " + rowId.toString() + " at position: " + String.valueOf(k)); |
} |
final LightUIElement editor = (LightUIElement) objEditor; |
if (editor instanceof LightUserControl && jsonLineContext.containsKey(editor.getUUID())) { |
((LightUserControl) editor)._setValueFromContext(jsonLineContext.get(editor.getUUID())); |
} else { |
System.out.println("LightUITable.setValueFromContext() - Unable to find element : id - " + element.getId() + " uuid - " + element.getUUID()); |
System.out.println("LightUITable.setValueFromContext() - In JSON : " + jsonLineContext.toJSONString()); |
throw new IllegalArgumentException( |
"Impossible to find value for editor: " + editor.getId() + " for row: " + rowId.toString() + " at position: " + String.valueOf(k)); |
} |
} |
} |
} else { |
for (int k = 0; k < editorsIndex.size(); k++) { |
final Object objEditor = row.getValues().get(editorsIndex.get(k)); |
if (!(objEditor instanceof IUserControl)) { |
throw new IllegalArgumentException("Impossible to find editor for row: " + rowId.toString() + " at position: " + String.valueOf(k)); |
} |
final LightUIElement editor = (LightUIElement) objEditor; |
if (editor instanceof IUserControl && jsonLineContext.containsKey(editor.getUUID())) { |
((IUserControl) editor).setValueFromContext(jsonLineContext.get(editor.getUUID())); |
} else { |
throw new IllegalArgumentException( |
"Impossible to find value for editor: " + editor.getId() + " for row: " + rowId.toString() + " at position: " + String.valueOf(k)); |
} |
} |
throw new IllegalArgumentException("Impossible to find row: " + rowId.toString()); |
} |
} else { |
throw new IllegalArgumentException("Impossible to find row: " + rowId.toString()); |
} |
} |
} |
334,21 → 547,22 |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
if (this.allowSelection) { |
json.put("allow-selection", true); |
json.put(ALLOW_SELECTION, true); |
} |
if (this.allowMultiSelection) { |
json.put(ALLOW_MULTI_SELECTION, true); |
} |
if (this.dynamicLoad) { |
json.put("dynamic-load", true); |
json.put(DYNAMIC_LOAD, true); |
} |
if (this.verticallyScrollable) { |
json.put("vertically-scrollable", true); |
if (!this.autoSelectFirstLine) { |
json.put(AUTO_SELECT_FIRST_LINE, false); |
} |
if (this.tableSpec != null) { |
json.put("table-spec", this.tableSpec.toJSON()); |
json.put(TABLE_SPEC, this.tableSpec.toJSON()); |
} |
if (this.elementCode != null) { |
json.put("element-code", this.elementCode); |
} |
json.put("line-per-row", this.linePerRow); |
json.put(LINE_PER_ROW, this.linePerRow); |
return json; |
} |
355,16 → 569,22 |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.allowSelection = JSONConverter.getParameterFromJSON(json, "allow-selection", Boolean.class, false); |
this.dynamicLoad = JSONConverter.getParameterFromJSON(json, "dynamic-load", Boolean.class, false); |
this.verticallyScrollable = JSONConverter.getParameterFromJSON(json, "vertically-scrollable", Boolean.class, false); |
this.elementCode = JSONConverter.getParameterFromJSON(json, "element-code", String.class); |
this.linePerRow = JSONConverter.getParameterFromJSON(json, "line-per-row", Integer.class); |
this.allowSelection = JSONConverter.getParameterFromJSON(json, ALLOW_SELECTION, Boolean.class, false); |
this.allowSelection = JSONConverter.getParameterFromJSON(json, ALLOW_MULTI_SELECTION, Boolean.class, false); |
this.dynamicLoad = JSONConverter.getParameterFromJSON(json, DYNAMIC_LOAD, Boolean.class, false); |
this.autoSelectFirstLine = JSONConverter.getParameterFromJSON(json, AUTO_SELECT_FIRST_LINE, Boolean.class, true); |
this.linePerRow = JSONConverter.getParameterFromJSON(json, LINE_PER_ROW, Integer.class); |
final JSONObject jsonRawContent = (JSONObject) JSONConverter.getParameterFromJSON(json, "table-spec", JSONObject.class); |
final JSONObject jsonRawContent = (JSONObject) JSONConverter.getParameterFromJSON(json, TABLE_SPEC, JSONObject.class); |
if (jsonRawContent != null) { |
this.tableSpec = new TableSpec(jsonRawContent); |
} |
} |
@Override |
public void destroy() { |
super.destroy(); |
this.selectionListeners.clear(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TreeItem.java |
---|
40,7 → 40,7 |
} |
public final String getId() { |
return id; |
return this.id; |
} |
public final void setId(String id) { |
48,7 → 48,7 |
} |
public String getLabel() { |
return label; |
return this.label; |
} |
public void setLabel(String label) { |
56,15 → 56,15 |
} |
public TreeItem getChild(int i) { |
return children.get(i); |
return this.children.get(i); |
} |
public int getChildCount() { |
return children.size(); |
return this.children.size(); |
} |
public final List<TreeItem> getChildren() { |
return children; |
return this.children; |
} |
public final void addChild(TreeItem item) { |
90,7 → 90,7 |
} |
public final boolean isSelected() { |
return isSelected; |
return this.isSelected; |
} |
public final void setSelected(boolean isSelected) { |
98,7 → 98,7 |
} |
public final Color getColor() { |
return color; |
return this.color; |
} |
public final void setColor(Color color) { |
106,7 → 106,7 |
} |
public final boolean isExpanded() { |
return expanded; |
return this.expanded; |
} |
public final void setExpanded(boolean expanded) { |
114,7 → 114,7 |
} |
public final String getIconId() { |
return iconId; |
return this.iconId; |
} |
public final void setRightIconId(String iconId) { |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/SearchSpec.java |
---|
23,21 → 23,21 |
public class SearchSpec implements Transferable { |
private String tableId; |
private List<SearchContent> content; |
private List<SearchContent> content = new ArrayList<SearchContent>(); |
public SearchSpec(final String tableId) { |
this.tableId = tableId; |
} |
public SearchSpec(final JSONObject json) { |
this.fromJSON(json); |
} |
public String getTableId() { |
public final String getTableId() { |
return this.tableId; |
} |
public List<SearchContent> getContent() { |
public final List<SearchContent> getContent() { |
return this.content; |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/TableContent.java |
---|
31,7 → 31,7 |
} |
public TableContent(final String tableId) { |
this.init(tableId, null); |
this.init(tableId, new ArrayList<Row>()); |
} |
public TableContent(final String tableId, final List<Row> rows) { |
42,38 → 42,65 |
this.fromJSON(json); |
} |
private void init(final String tableId, final List<Row> rows) { |
private final void init(final String tableId, final List<Row> rows) { |
this.tableId = tableId; |
if (rows != null) { |
this.rows = rows; |
} else { |
this.rows = new ArrayList<Row>(); |
} |
this.rows = rows; |
} |
public String getTableId() { |
public final String getTableId() { |
return this.tableId; |
} |
public void setTableId(final String tableId) { |
public final void setTableId(final String tableId) { |
this.tableId = tableId; |
} |
public List<Row> getRows() { |
return this.rows; |
public final synchronized Row getRow(final int index) { |
return this.rows.get(index); |
} |
public void setRows(List<Row> rows) { |
public final synchronized int getRowsCount() { |
return this.rows.size(); |
} |
public final synchronized boolean addRow(final Row row) { |
return this.rows.add(row); |
} |
public final synchronized Row setRow(final int index, final Row row) { |
return this.rows.set(index, row); |
} |
public final synchronized Row removeRow(final int index) { |
return this.rows.remove(index); |
} |
public final synchronized boolean removeRow(final Row row) { |
return this.rows.remove(row); |
} |
public final synchronized void setRows(List<Row> rows) { |
this.rows = rows; |
} |
public final synchronized void clearRows() { |
this.rows.clear(); |
} |
/** |
* @return a copy of the list |
*/ |
public final synchronized List<Row> getRows(){ |
return new ArrayList<Row>(this.rows); |
} |
@Override |
public String toString() { |
return "TableContent of " + this.tableId + " lines count : " + getRows().size(); |
public synchronized String toString() { |
return "TableContent of " + this.tableId + " lines count : " + this.getRowsCount(); |
} |
@Override |
public JSONObject toJSON() { |
public synchronized JSONObject toJSON() { |
final JSONObject result = new JSONObject(); |
result.put("class", "TableContent"); |
result.put("table-id", this.tableId); |
82,14 → 109,15 |
} |
@Override |
public void fromJSON(final JSONObject json) { |
this.tableId = (String) JSONConverter.getParameterFromJSON(json, "table-id", String.class); |
final JSONArray jsonRows = (JSONArray) JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class); |
public synchronized void fromJSON(final JSONObject json) { |
this.tableId = JSONConverter.getParameterFromJSON(json, "table-id", String.class); |
final JSONArray jsonRows = JSONConverter.getParameterFromJSON(json, "rows", JSONArray.class); |
if (jsonRows != null) { |
this.rows = new ArrayList<Row>(); |
final List<Row> listRows = new ArrayList<Row>(); |
for (final Object o : jsonRows) { |
this.rows.add(new Row((JSONObject) JSONConverter.getObjectFromJSON(o, JSONObject.class))); |
listRows.add(new Row(JSONConverter.getObjectFromJSON(o, JSONObject.class))); |
} |
this.setRows(listRows); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIListRow.java |
---|
Nouveau fichier |
0,0 → 1,69 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.io.JSONConverter; |
import net.minidev.json.JSONObject; |
public class LightUIListRow extends LightUIPanel { |
private Number rowId; |
// Init from json constructor |
public LightUIListRow(final JSONObject json) { |
super(json); |
} |
// Clone constructor |
public LightUIListRow(final LightUIListRow listItem) { |
super(listItem); |
this.rowId = listItem.rowId; |
} |
public LightUIListRow(final LightUIList parent, final Number rowId) { |
super(parent.getId() + ".item.panel." + rowId.toString()); |
this.rowId = rowId; |
this.setType(TYPE_LIST_ROW); |
this.setFillHeight(false); |
} |
public LightUIListRow(final LightUIList parent, final Number id, final String label) { |
this(parent, id); |
final LightUILine line = new LightUILine(); |
line.addChild(new LightUILabel(this.getId() + ".label", label)); |
this.addChild(line); |
} |
public Number getRowId() { |
return this.rowId; |
} |
public LightUIListRow clone() { |
return new LightUIListRow(this); |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put("row-id", this.getRowId()); |
return json; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.rowId = JSONConverter.getParameterFromJSON(json, "row-id", Number.class); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/ColumnsSpec.java |
---|
13,6 → 13,7 |
package org.openconcerto.ui.light; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.utils.io.Transferable; |
63,9 → 64,6 |
if (columns == null) { |
throw new IllegalArgumentException("null columns"); |
} |
if (columns.isEmpty()) { |
throw new IllegalArgumentException("empty columns"); |
} |
this.columns = columns; |
// Possible checks |
72,9 → 70,6 |
if (possibleColumnIds == null) { |
throw new IllegalArgumentException("null possible column ids"); |
} |
if (possibleColumnIds.isEmpty()) { |
throw new IllegalArgumentException("empty possible column ids"); |
} |
this.possibleColumnIds = possibleColumnIds; |
// Sort assign |
82,62 → 77,62 |
} |
public String getId() { |
public final String getId() { |
return this.id; |
} |
public List<String> getPossibleColumnIds() { |
public final List<String> getPossibleColumnIds() { |
return this.possibleColumnIds; |
} |
public List<String> getSortedIds() { |
public final List<String> getSortedIds() { |
return this.sortedIds; |
} |
public int getFixedColumns() { |
public final int getFixedColumns() { |
return this.fixedColumns; |
} |
public int getColumnCount() { |
public final int getColumnCount() { |
return this.columns.size(); |
} |
public ColumnSpec getColumn(int i) { |
public final ColumnSpec getColumn(int i) { |
return this.columns.get(i); |
} |
public ColumnSpec setColumn(int i, final ColumnSpec column) { |
public final ColumnSpec setColumn(int i, final ColumnSpec column) { |
return this.columns.set(i, column); |
} |
public Boolean isAdaptWidth() { |
public final Boolean isAdaptWidth() { |
return this.adaptWidth; |
} |
public void setAdaptWidth(final boolean adaptWidth) { |
public final void setAdaptWidth(final boolean adaptWidth) { |
this.adaptWidth = adaptWidth; |
} |
public Boolean isAllowMove() { |
public final Boolean isAllowMove() { |
return this.allowMove; |
} |
public void setAllowMove(final boolean allowMove) { |
public final void setAllowMove(final boolean allowMove) { |
this.allowMove = allowMove; |
} |
public Boolean isAllowResize() { |
public final Boolean isAllowResize() { |
return this.allowResize; |
} |
public void setAllowResize(final boolean allowResize) { |
public final void setAllowResize(final boolean allowResize) { |
this.allowResize = allowResize; |
} |
public List<String> getColumnsIds() { |
ArrayList<String> result = new ArrayList<String>(this.columns.size()); |
final ArrayList<String> result = new ArrayList<String>(this.columns.size()); |
for (ColumnSpec c : this.columns) { |
result.add(c.getId()); |
} |
144,8 → 139,7 |
return result; |
} |
public void setUserPrefs(final Document columnsPrefs) { |
public final boolean setUserPrefs(final Document columnsPrefs) { |
if (columnsPrefs != null) { |
// user preferences application |
final Element rootElement = columnsPrefs.getRootElement(); |
173,9 → 167,9 |
throw new IllegalArgumentException("ColumnSpec setPrefs - Invalid column node for " + columnId + ", it must have attribute width, min-width, max-width"); |
} |
final int width = Integer.parseInt(xmlColumn.getAttribute("width").getValue()); |
final int maxWidth = Integer.parseInt(xmlColumn.getAttribute("max-width").getValue()); |
final int minWidth = Integer.parseInt(xmlColumn.getAttribute("min-width").getValue()); |
final double width = Double.parseDouble(xmlColumn.getAttribute("width").getValue()); |
final double maxWidth = Double.parseDouble(xmlColumn.getAttribute("max-width").getValue()); |
final double minWidth = Double.parseDouble(xmlColumn.getAttribute("min-width").getValue()); |
columnSpec.setPrefs(width, maxWidth, minWidth); |
if (i != j) { |
182,6 → 176,8 |
final ColumnSpec swap = this.columns.get(i); |
this.columns.set(i, this.columns.get(j)); |
this.columns.set(j, swap); |
i--; |
} |
find = true; |
break; |
188,27 → 184,16 |
} |
} |
if (!find) { |
System.out.println("XML columns preferences does'nt contain this column: " + columnId); |
return false; |
} |
} |
} else { |
System.out.println("ColumnsSpec.setUserPrefs() - Incorrect columns count in XML for ColumnsSpec: " + this.id); |
return false; |
} |
} |
return true; |
} |
public Document createDefaultXmlPref() { |
final Element rootElement = new Element("list"); |
for (final ColumnSpec column : this.columns) { |
final Element columnElement = column.createXmlColumnPref(); |
rootElement.addContent(columnElement); |
} |
final Document xmlConf = new Document(rootElement); |
return xmlConf; |
} |
@Override |
public void writeExternal(ObjectOutput out) throws IOException { |
out.writeUTF(this.id); |
225,15 → 210,15 |
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
this.id = in.readUTF(); |
this.fixedColumns = in.readInt(); |
this.columns = (List<ColumnSpec>) in.readObject(); |
this.possibleColumnIds = (List<String>) in.readObject(); |
this.sortedIds = (List<String>) in.readObject(); |
this.columns = CollectionUtils.castList((List<?>) in.readObject(), ColumnSpec.class); |
this.possibleColumnIds = CollectionUtils.castList((List<?>) in.readObject(), String.class); |
this.sortedIds = CollectionUtils.castList((List<?>) in.readObject(), String.class); |
this.allowMove = in.readBoolean(); |
this.allowResize = in.readBoolean(); |
this.adaptWidth = in.readBoolean(); |
} |
public List<Object> getDefaultValues() { |
public final List<Object> getDefaultValues() { |
final List<Object> l = new ArrayList<Object>(); |
for (ColumnSpec column : this.columns) { |
final Object v = column.getDefaultValue(); |
242,7 → 227,7 |
return l; |
} |
public ColumnSpec getColumn(String id) { |
public final ColumnSpec getColumn(String id) { |
for (ColumnSpec c : this.columns) { |
if (c.getId().equals(id)) { |
return c; |
251,7 → 236,7 |
return null; |
} |
public ColumnSpec getColumnWithEditor(String id) { |
public final ColumnSpec getColumnWithEditor(String id) { |
for (ColumnSpec c : this.columns) { |
LightUIElement editor = c.getEditor(); |
if (editor != null && c.getEditor().getId().equals(id)) { |
290,29 → 275,18 |
@Override |
public void fromJSON(final JSONObject json) { |
this.id = (String) JSONConverter.getParameterFromJSON(json, "id", String.class); |
this.fixedColumns = (Integer) JSONConverter.getParameterFromJSON(json, "fixed-columns", Integer.class); |
this.adaptWidth = (Boolean) JSONConverter.getParameterFromJSON(json, "adapt-width", Boolean.class, false); |
this.allowMove = (Boolean) JSONConverter.getParameterFromJSON(json, "allow-move", Boolean.class, false); |
this.allowResize = (Boolean) JSONConverter.getParameterFromJSON(json, "allow-resize", Boolean.class, false); |
final JSONArray jsonSortedIds = (JSONArray) JSONConverter.getParameterFromJSON(json, "sorted-ids", JSONArray.class, null); |
if (jsonSortedIds != null) { |
this.sortedIds = (List<String>) (List<?>) jsonSortedIds; |
} |
final JSONArray jsonPossibleColumnIds = (JSONArray) JSONConverter.getParameterFromJSON(json, "possible-column-ids", JSONArray.class, null); |
if (jsonPossibleColumnIds != null) { |
this.possibleColumnIds = (List<String>) (List<?>) jsonPossibleColumnIds; |
} |
this.id = JSONConverter.getParameterFromJSON(json, "id", String.class); |
this.fixedColumns = JSONConverter.getParameterFromJSON(json, "fixed-columns", Integer.class); |
this.adaptWidth = JSONConverter.getParameterFromJSON(json, "adapt-width", Boolean.class, false); |
this.allowMove = JSONConverter.getParameterFromJSON(json, "allow-move", Boolean.class, false); |
this.allowResize = JSONConverter.getParameterFromJSON(json, "allow-resize", Boolean.class, false); |
this.sortedIds = CollectionUtils.castList(JSONConverter.getParameterFromJSON(json, "sorted-ids", List.class, new ArrayList<String>()), String.class); |
this.possibleColumnIds = CollectionUtils.castList(JSONConverter.getParameterFromJSON(json, "possible-column-ids", List.class, new ArrayList<String>()), String.class); |
final JSONArray jsonColumns = (JSONArray) JSONConverter.getParameterFromJSON(json, "columns", JSONArray.class, null); |
final List<JSONObject> jsonColumns = CollectionUtils.castList(JSONConverter.getParameterFromJSON(json, "columns", JSONArray.class, null), JSONObject.class); |
if (jsonColumns != null) { |
final int columnsSize = jsonColumns.size(); |
for (int i = 0; i < columnsSize; i++) { |
final Object objColumnSpec = jsonColumns.get(i); |
if (!(objColumnSpec instanceof JSONObject)) { |
throw new IllegalArgumentException("invalid value for 'columns', List<ColumnSpec> expected"); |
} |
this.columns.add(new ColumnSpec((JSONObject) objColumnSpec)); |
for (final JSONObject jsonColumn : jsonColumns) { |
this.columns.add(new ColumnSpec(jsonColumn)); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/CustomEditorProvider.java |
---|
13,8 → 13,6 |
package org.openconcerto.ui.light; |
public interface CustomEditorProvider { |
public LightUIElement createUIElement(String id); |
public abstract class CustomEditorProvider { |
public abstract LightUIElement createUIElement(final String id); |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUIButton.java |
---|
58,4 → 58,10 |
listener.actionPerformed(new ActionEvent(this, 1, "click")); |
} |
} |
@Override |
public void destroy() { |
super.destroy(); |
this.clickListeners.clear(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/light/LightUITextArea.java |
---|
17,7 → 17,7 |
import net.minidev.json.JSONObject; |
public class LightUITextArea extends LightUIElement implements IUserControl { |
public class LightUITextArea extends LightUserControl { |
private int nbLine = 4; |
70,13 → 70,13 |
} |
@Override |
public void setValueFromContext(final Object value) { |
public void _setValueFromContext(final Object value) { |
this.setValue((String) JSONConverter.getObjectFromJSON(value, String.class)); |
} |
@Override |
public Object getValueFromContext() { |
return this.getValue(); |
public Object getValueForContext() { |
return (this.getValue() == null) ? null : ((this.getValue().trim().equals("")) ? null : this.getValue()); |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ValueWrapperFactory.java |
---|
43,11 → 43,12 |
if (isValueWrapper(comp, c)) { |
return (ValueWrapper<Z>) comp; |
} else if (getConvertorVW(comp, c) != null) { |
// e.g. comp is ValueWrapper<X> and there's a convertor between X and Z |
return getConvertorVW(comp, c); |
} else if (isValueObject(comp, c)) { |
return new ValueWrapperFromVO<Z>((MutableValueObject) comp); |
return new ValueWrapperFromVO<Z>((MutableValueObject<Z>) comp); |
} else if (comp instanceof JFormattedTextField && JFormattedTextFieldValueWrapper.isCompatible((JFormattedTextField) comp, c)) { |
return new JFormattedTextFieldValueWrapper((JFormattedTextField) comp, c); |
return new JFormattedTextFieldValueWrapper<Z>((JFormattedTextField) comp, c); |
} else if (Boolean.class.isAssignableFrom(c)) { |
return (ValueWrapper<Z>) new BooleanValueWrapper((JToggleButton) comp); |
} else if (String.class.isAssignableFrom(c)) |
61,7 → 62,7 |
private static <Z> boolean isValueWrapper(final JComponent comp, final Class<Z> c) { |
if (!(comp instanceof ValueWrapper)) |
return false; |
return ReflectUtils.isCastable((ValueWrapper) comp, ValueWrapper.class, c); |
return ReflectUtils.isCastable((ValueWrapper<?>) comp, ValueWrapper.class, c); |
} |
@SuppressWarnings("unchecked") |
72,6 → 73,7 |
final List<Class<?>> typeArguments = ReflectUtils.getTypeArguments(vw, ValueWrapper.class); |
if (typeArguments.size() == 0) |
throw new IllegalArgumentException("unable to find type arguments of " + vw + " \n(you should define a class that specify them, eg class C extends ValueWrapper<Integer>)"); |
assert typeArguments.size() == 1 : "Wrong number of arguments for ValueWrapper : " + typeArguments; |
final Class<?> typeArgument = typeArguments.get(0); |
return createCVW(vw, typeArgument, c); |
} |
87,7 → 89,7 |
private static <Z> boolean isValueObject(final JComponent comp, final Class<Z> c) { |
if (!(comp instanceof MutableValueObject)) |
return false; |
return ReflectUtils.isCastable((MutableValueObject) comp, ValueObject.class, c); |
return ReflectUtils.isCastable((MutableValueObject<?>) comp, ValueObject.class, c); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/ui/JDateTime.java |
---|
99,6 → 99,7 |
this.add(this.time, c); |
this.resetValue(); |
updateValue(); |
} |
protected void updateValue() { |
/trunk/OpenConcerto/src/org/openconcerto/ui/translation/messages_en.properties |
---|
6,6 → 6,8 |
saveWindowState=Error while saving size and position of the window |
prefCreationError=Error while creating the preference panel |
missingFile=The file doesn\u2019t exist : {0} |
userExit.question=Do you really want to quit ? |
userExit.title=Quit |
/trunk/OpenConcerto/src/org/openconcerto/ui/translation/messages_fr.properties |
---|
6,6 → 6,8 |
saveWindowState=Impossible de sauvegarder la taille et la position de la fenêtre |
prefCreationError=Impossible de créer le panneau de préférence |
missingFile=Le fichier n\u2019existe pas : {0} |
userExit.question=Voulez-vous vraiment quitter ? |
userExit.title=Quitter |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/Login.java |
---|
138,7 → 138,7 |
return res; |
} |
private final List<SQLRow> findUser(final String login) { |
public final List<SQLRow> findUser(final String login) { |
final SQLSelect selUser = new SQLSelect(); |
selUser.addSelect(this.userT.getField("ID")); |
selUser.addSelect(this.userT.getField("PASSWORD")); |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/RadioButtons.java |
---|
48,7 → 48,8 |
public RadioButtons(String colName) { |
super(); |
this.colName = colName; |
this.tm = Transformer.nopTransformer(); |
// ATTN javac 1.6 cannot infer the generic type |
this.tm = Transformer.<String> nopTransformer(); |
} |
public final RadioButtons initLocalization(final TM tm) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/ConnexionPanel.java |
---|
149,6 → 149,9 |
public ConnexionPanel(final Runnable r, final JImage imageLogo, final boolean societeSelector, final boolean allowStoredPass) { |
super(); |
if (r == null) { |
throw new IllegalArgumentException("null runnable"); |
} |
this.login = new Login(Configuration.getInstance().getRoot()); |
this.societeSelector = societeSelector; |
372,14 → 375,10 |
private boolean areFieldsValidated() { |
if (this.societeSelector) { |
final SQLRow selectedRow = this.comboSociete.getSelectedRow(); |
// don't use isData() since it calls isArchived() and since ComboRequest doesn't include |
// ARCHIVE field this triggers a request |
if (selectedRow == null || selectedRow.isUndefined()) { |
if (this.comboSociete.isEmpty()) { |
return false; |
} |
} |
if (this.textLogin == null || this.textLogin.isEmpty() || this.textPassWord == null) { |
return false; |
} else { |
486,12 → 485,16 |
SwingUtilities.invokeLater(new Runnable() { |
@Override |
public void run() { |
ConnexionPanel.this.reloadPanel.setMode(ReloadPanel.MODE_BLINK); |
JOptionPane.showMessageDialog(ConnexionPanel.this, TM.getTM().translate("loginPanel." + error, userName)); |
// Guillaume wants this for the Nego |
if (Login.UNKNOWN_USER.equals(error)) |
ConnexionPanel.this.textLogin.setValue(ConnexionPanel.this.adminLogin); |
setConnecting(false); |
try { |
ConnexionPanel.this.reloadPanel.setMode(ReloadPanel.MODE_BLINK); |
JOptionPane.showMessageDialog(ConnexionPanel.this, TM.getTM().translate("loginPanel." + error, userName)); |
// Guillaume wants this for the Nego |
if (Login.UNKNOWN_USER.equals(error)) |
ConnexionPanel.this.textLogin.setValue(ConnexionPanel.this.adminLogin); |
setConnecting(false); |
} catch (Exception e) { |
e.printStackTrace(); |
} |
} |
}); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/SoftwareInfoPanel.java |
---|
22,6 → 22,7 |
import org.openconcerto.sql.users.rights.UserRightsManager; |
import org.openconcerto.ui.FormLayouter; |
import org.openconcerto.ui.component.HTMLTextField; |
import org.openconcerto.utils.BaseDirs; |
import org.openconcerto.utils.ProductInfo; |
import org.openconcerto.utils.SystemInfo; |
import org.openconcerto.utils.cc.IFactory; |
87,9 → 88,16 |
if (propsConf != null && propsConf.isUsingSSH()) { |
res.put(Info.SECURE_LINK, propsConf.getWanHostAndPort()); |
} |
res.put(Info.DB_URL, conf.getSystemRoot().getDataSource().getUrl()); |
final String logs = propsConf == null ? "" : " ; " + SystemInfo.getLink(TM.tr("infoPanel.logs"), propsConf.getLogDir().toURI(), html); |
res.put(Info.DIRS, SystemInfo.getLink(TM.tr("infoPanel.docs"), conf.getWD().toURI(), html) + logs); |
if (conf != null) |
res.put(Info.DB_URL, conf.getSystemRoot().getDataSource().getUrl()); |
if (conf != null) { |
final String logs = propsConf == null ? "" : " ; " + SystemInfo.getLink(TM.tr("infoPanel.logs"), propsConf.getLogDir().toURI(), html); |
final BaseDirs baseDirs = conf.getBaseDirs(); |
String dirs = " ; " + SystemInfo.getLink(TM.tr("infoPanel.dataDir"), baseDirs.getAppDataFolder().toURI(), html); |
dirs = dirs + " ; " + SystemInfo.getLink(TM.tr("infoPanel.prefsDir"), baseDirs.getPreferencesFolder().toURI(), html); |
dirs = dirs + " ; " + SystemInfo.getLink(TM.tr("infoPanel.cacheDir"), baseDirs.getCacheFolder().toURI(), html); |
res.put(Info.DIRS, SystemInfo.getLink(TM.tr("infoPanel.docs"), conf.getWD().toURI(), html) + logs + dirs); |
} |
return res; |
} |
116,7 → 124,11 |
if (secureLink != null) { |
this.l.add(TM.tr("infoPanel.secureLink"), new JLabel(secureLink)); |
} |
this.l.add(TM.tr("infoPanel.dbURL"), new JLabel(infos.get(Info.DB_URL))); |
this.l.add(TM.tr("infoPanel.dirs"), new HTMLTextField(infos.get(Info.DIRS))); |
final JLabel dbURL = new JLabel(infos.get(Info.DB_URL)); |
if (dbURL != null) |
this.l.add(TM.tr("infoPanel.dbURL"), dbURL); |
final String dirs = infos.get(Info.DIRS); |
if (dirs != null) |
this.l.add(TM.tr("infoPanel.dirs"), new HTMLTextField(dirs)); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SearchInfo.java |
---|
13,6 → 13,7 |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.view.search.SearchList; |
import org.openconcerto.sql.view.search.TextSearchSpec; |
import org.openconcerto.sql.view.search.TextSearchSpec.Mode; |
23,6 → 24,7 |
import java.util.List; |
public class SearchInfo { |
// TODO: add notion of operator |
private final SearchList list = new SearchList(); |
private final List<String> texts = new ArrayList<String>(); |
32,7 → 34,7 |
final SearchContent param = params.getContent().get(i); |
final String col = param.getColumn(); |
final String type = param.getType(); |
final String text = param.getText(); |
final String[] tTexts = param.getText().split(" "); |
Mode mode = Mode.CONTAINS; |
if (type.equals("contains")) { |
47,10 → 49,11 |
throw new IllegalArgumentException("mode " + type + " not supported"); |
} |
System.err.println("SearchInfo.SearchInfo() column:" + col + "type:" + type + " text:" + text); |
System.err.println("SearchInfo.SearchInfo() ignoring column " + col); |
this.list.addSearchItem(new TextSearchSpec(text, mode)); |
this.texts.add(text); |
for (final String text : tTexts) { |
this.list.addSearchItem(new TextSearchSpec(text, mode)); |
this.texts.add(text); |
Log.get().info("searching column:" + col + "type:" + type + " text:" + text); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightAutoCompleteComboBox.java |
---|
Nouveau fichier |
0,0 → 1,104 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.sqlobject.IComboSelectionItem; |
import org.openconcerto.ui.light.LightUIComboBox; |
import org.openconcerto.ui.light.LightUIComboBoxElement; |
import org.openconcerto.utils.io.JSONConverter; |
import java.util.Arrays; |
import java.util.List; |
import java.util.Locale; |
import java.util.regex.Pattern; |
import net.minidev.json.JSONObject; |
public class LightAutoCompleteComboBox extends LightUIComboBox { |
private static final String FILTER = "filter"; |
private final static Pattern QUERY_SPLIT_PATTERN = Pattern.compile("\\s+"); |
private String filter; |
private ComboSQLRequest request; |
public LightAutoCompleteComboBox(final JSONObject json) { |
super(json); |
} |
public LightAutoCompleteComboBox(final String id) { |
super(id); |
this.setType(TYPE_AUTOCOMPLETE_COMBOBOX); |
} |
public void setComboRequest(final ComboSQLRequest request) { |
this.request = request; |
this.setFilter(""); |
this.setAlreadyFilled(true); |
} |
public ComboSQLRequest getComboRequest() { |
return this.request; |
} |
public String getFilter() { |
return this.filter; |
} |
public void setFilter(final String filter) { |
this.filter = filter; |
this.applyFilter(); |
} |
private void applyFilter() { |
if (this.request != null) { |
Integer selectedId = null; |
if (this.hasSelectedValue()) { |
selectedId = this.getSelectedValue().getId(); |
} |
this.clearValues(); |
if (this.hasNotSpecifedLine()) { |
this.addValue(LightUIComboBox.getDefaultValue()); |
} |
final Where where = this.hasSelectedValue() ? new Where(this.request.getPrimaryTable().getKey(), "=", this.getSelectedValue().getId()) : null; |
final List<IComboSelectionItem> items = this.request.getComboItems(true, Arrays.asList(QUERY_SPLIT_PATTERN.split(this.filter)), Locale.getDefault(), where); |
System.err.println("LightAutoCompleteComboBox.applyFilter() - items count: " + items.size()); |
for (final IComboSelectionItem item : items) { |
this.addValue(new LightUIComboBoxElement(item.getId(), item.getLabel())); |
} |
this.setSelectedId(selectedId); |
} |
} |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
json.put(FILTER, this.filter); |
return json; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
this.filter = JSONConverter.getParameterFromJSON(json, FILTER, String.class); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightUIPanelFiller.java |
---|
15,25 → 15,23 |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.PropsConfiguration; |
import org.openconcerto.sql.model.FieldPath; |
import org.openconcerto.sql.model.Constraint; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLSyntax.ConstraintType; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.model.graph.Path; |
import org.openconcerto.sql.sqlobject.ElementComboBoxUtils; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.sqlobject.IComboSelectionItem; |
import org.openconcerto.ui.light.LightUIComboBox; |
import org.openconcerto.ui.light.LightUIComboBoxElement; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.LightUILine; |
import org.openconcerto.ui.light.LightUIPanel; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.io.JSONConverter; |
import java.util.Calendar; |
import java.util.Date; |
import java.util.List; |
import java.util.Set; |
/** |
* Fill value from default or database |
64,11 → 62,11 |
this.fillFromRow(this.panel, configuration, row); |
} |
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLRowAccessor row) { |
private void fillFromRow(final LightUIPanel panel, final PropsConfiguration configuration, SQLRowAccessor sqlRow) { |
final int panelChildCount = panel.getChildrenCount(); |
// Convert as sqlrow if possible to get all values from db |
if (row.hasID()) { |
row = row.asRow(); |
if (sqlRow.hasID()) { |
sqlRow = sqlRow.asRow(); |
} |
for (int i = 0; i < panelChildCount; i++) { |
final LightUILine panelChild = panel.getChild(i, LightUILine.class); |
75,55 → 73,86 |
final int lineChildCount = panelChild.getChildrenCount(); |
for (int j = 0; j < lineChildCount; j++) { |
final LightUIElement element = panelChild.getChild(j); |
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(element.getId()); |
final SQLField sqlField = configuration.getFieldMapper().getSQLFieldForItem(element.getId()); |
SQLRowAccessor sqlRowTmp = this.getSQLRowForField(sqlRow, sqlField); |
if (sqlRowTmp == null) { |
throw new IllegalArgumentException("Impossible to reach the field: " + sqlField.getName() + " from table " + sqlRow.getTable().getName()); |
} |
int type = element.getType(); |
if (type == LightUIElement.TYPE_TEXT_FIELD || type == LightUIElement.TYPE_TEXT_AREA) { |
if (field == null) { |
if (sqlField == null) { |
Log.get().severe("No field found for text field : " + element.getId()); |
continue; |
} |
element.setValue(row.getString(field.getName())); |
} else if (type == LightUIElement.TYPE_COMBOBOX) { |
element.setValue(sqlRowTmp.getString(sqlField.getName())); |
} else if (sqlField != null && sqlField.isKey() && (type == LightUIElement.TYPE_COMBOBOX || type == LightUIElement.TYPE_AUTOCOMPLETE_COMBOBOX)) { |
// send: id,value |
final LightUIComboBox combo = (LightUIComboBox) element; |
if (!combo.isFillFromConvertor()) { |
SQLTable foreignTable = field.getForeignTable(); |
final List<SQLField> fieldsToFetch = configuration.getDirectory().getElement(foreignTable).getComboRequest().getFields(); |
if (row.getObject(field.getName()) != null) { |
final Where where = new Where(foreignTable.getKey(), "=", row.getForeignID(field.getName())); |
final SQLRowValues graph = ElementComboBoxUtils.getGraphToFetch(configuration, foreignTable, fieldsToFetch); |
final List<Tuple2<Path, List<FieldPath>>> expanded = ElementComboBoxUtils.expandGroupBy(graph, configuration.getDirectory()); |
List<SQLRowValues> fetchedRows = ElementComboBoxUtils.fetchRows(graph, where); |
if (fetchedRows.size() > 1) { |
throw new IllegalStateException("multiple rows fetched, id: " + ((row.hasID()) ? row.getID() : "undefined") + " table: " + row.getTable().getName()); |
} |
for (final SQLRowValues vals : fetchedRows) { |
LightUIComboBoxElement value = ElementComboBoxUtils.createLightUIItem(expanded, vals); |
combo.setSelectedValue(value); |
} |
} else { |
element.setValue(null); |
LightUIComboBoxElement value = null; |
final Number foreignID = sqlRowTmp.getForeignIDNumber(sqlField.getName()); |
if (foreignID != null) { |
final SQLTable foreignTable = sqlField.getForeignTable(); |
final ComboSQLRequest req = configuration.getDirectory().getElement(foreignTable).getComboRequest(); |
final IComboSelectionItem comboItem = req.getComboItem(foreignID.intValue()); |
if (comboItem != null) { |
value = new LightUIComboBoxElement(comboItem.getId()); |
value.setValue1(comboItem.getLabel()); |
} |
} |
combo.setSelectedValue(value); |
} else if (type == LightUIElement.TYPE_CHECKBOX) { |
if (row.getBoolean(field.getName())) { |
if (sqlRowTmp.getObject(sqlField.getName()) != null && sqlRowTmp.getBoolean(sqlField.getName())) { |
element.setValue("true"); |
} else { |
element.setValue("false"); |
} |
} else if (type == LightUIElement.TYPE_DATE) { |
Calendar date = row.getDate(field.getName()); |
Calendar date = sqlRowTmp.getDate(sqlField.getName()); |
if (date != null) { |
element.setValue(JSONConverter.getJSON(date).toString()); |
} |
} else if (type == LightUIElement.TYPE_PANEL) { |
this.fillFromRow((LightUIPanel) element, configuration, row); |
this.fillFromRow((LightUIPanel) element, configuration, sqlRowTmp); |
} else if (type == LightUIElement.TYPE_SLIDER) { |
final Integer value = sqlRowTmp.getInt(sqlField.getName()); |
if (value != null) { |
element.setValue(value.toString()); |
} |
} |
} |
} |
} |
public SQLRowAccessor getSQLRowForField(final SQLRowAccessor sqlRow, final SQLField sqlField) { |
SQLRowAccessor sqlRowResult = sqlRow; |
if (sqlField != null && !sqlField.getTable().getName().equals(sqlRow.getTable().getName())) { |
sqlRowResult = this.findSQLRow(sqlRow, sqlField); |
} |
return sqlRowResult; |
} |
public SQLRowAccessor findSQLRow(final SQLRowAccessor sqlRow, final SQLField sqlField) { |
final Set<Constraint> constraints = sqlRow.getTable().getAllConstraints(); |
for (final Constraint constraint : constraints) { |
if (constraint.getType().equals(ConstraintType.FOREIGN_KEY)) { |
// FIXME: this doesn't work when foreign key is composed of more than one field |
final String firstFkCols = constraint.getCols().get(0); |
final SQLRowAccessor fkRow = sqlRow.getForeign(firstFkCols); |
if (fkRow != null) { |
if (fkRow.getTable().getName().equals(sqlField.getTable().getName())) { |
return fkRow; |
} else { |
final SQLRowAccessor sqlRowResult = this.findSQLRow(fkRow, sqlField); |
if (sqlRowResult != null) { |
return sqlRowResult; |
} |
} |
} |
} |
} |
return null; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightForeignRowValuesTableOffline.java |
---|
Nouveau fichier |
0,0 → 1,91 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.view.list.ITableModel; |
import org.openconcerto.sql.view.list.SQLTableModelLinesSourceOffline; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.SearchSpec; |
import org.openconcerto.ui.light.TableContent; |
import java.util.concurrent.Future; |
import net.minidev.json.JSONObject; |
public class LightForeignRowValuesTableOffline extends LightRowValuesTable { |
private SQLField foreignField; |
private Number parentRowId; |
public LightForeignRowValuesTableOffline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField, final Number parentRowId) { |
super(configuration, userId, id, model); |
this.foreignField = foreignField; |
this.parentRowId = parentRowId; |
this.init(); |
} |
public LightForeignRowValuesTableOffline(final LightForeignRowValuesTableOffline table) { |
super(table); |
this.foreignField = table.foreignField; |
this.parentRowId = table.parentRowId; |
this.init(); |
} |
private final void init() { |
if (this.getTableSpec().getContent() == null) { |
this.getTableSpec().setContent(new TableContent(this.getId())); |
} |
} |
public final SQLField getForeignField() { |
return this.foreignField; |
} |
public final Number getParentRowId() { |
return this.parentRowId; |
} |
public Future<?> commitRows() { |
return ((SQLTableModelLinesSourceOffline) this.getModel().getLinesSource()).commit(); |
} |
public void addNewRow(final SQLRowValues sqlRow) { |
((SQLTableModelLinesSourceOffline) this.getModel().getLinesSource()).add(sqlRow); |
} |
@Override |
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) { |
// TODO: Implement search in offline table |
this.getModel().fireTableRowsInserted(0, Integer.MAX_VALUE); |
} |
@Override |
public LightUIElement clone() { |
return new LightForeignRowValuesTableOffline(this); |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
if (this.getTableSpec().getContent() != null) { |
this.getTableSpec().getContent().clearRows(); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightForeignRowValuesTableOnline.java |
---|
Nouveau fichier |
0,0 → 1,51 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.view.list.ITableModel; |
import org.openconcerto.ui.light.LightUIElement; |
public class LightForeignRowValuesTableOnline extends LightRowValuesTableOnline { |
private SQLField foreignField; |
private Number parentRowId; |
public LightForeignRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model, final SQLField foreignField, final Number parentRowId) { |
super(configuration, userId, id, model); |
this.foreignField = foreignField; |
this.parentRowId = parentRowId; |
} |
public LightForeignRowValuesTableOnline(final LightForeignRowValuesTableOnline table) { |
super(table); |
this.foreignField = table.foreignField; |
this.parentRowId = table.parentRowId; |
} |
public final SQLField getForeignField() { |
return this.foreignField; |
} |
public final Number getParentRowId() { |
return this.parentRowId; |
} |
@Override |
public LightUIElement clone() { |
return new LightForeignRowValuesTableOnline(this); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/GroupToLightUIConvertor.java |
---|
18,7 → 18,7 |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.FieldMapper; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.request.RowItemDesc; |
import org.openconcerto.sql.view.EditPanel.EditMode; |
import org.openconcerto.ui.group.Group; |
26,7 → 26,6 |
import org.openconcerto.ui.group.LayoutHints; |
import org.openconcerto.ui.light.CustomEditorProvider; |
import org.openconcerto.ui.light.LightUICheckBox; |
import org.openconcerto.ui.light.LightUIComboBox; |
import org.openconcerto.ui.light.LightUIDate; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.LightUIFrame; |
38,6 → 37,8 |
import org.openconcerto.utils.i18n.TranslationManager; |
import java.awt.Color; |
import java.math.BigDecimal; |
import java.math.BigInteger; |
import java.sql.Timestamp; |
import java.util.Date; |
import java.util.HashMap; |
48,7 → 49,6 |
private PropsConfiguration configuration; |
private FieldMapper mapper; |
private Map<String, CustomEditorProvider> customEditorProviders = new HashMap<String, CustomEditorProvider>(); |
private Map<String, ConvertorModifer> modifers = new HashMap<String, ConvertorModifer>(); |
public GroupToLightUIConvertor(PropsConfiguration conf) { |
this(conf, 4); |
63,7 → 63,7 |
} |
} |
public LightEditFrame convert(final Group group, final SQLRowValues defaultRow, final LightUIFrame parentFrame, final EditMode editMode) { |
public LightEditFrame convert(final Group group, final SQLRowAccessor defaultRow, final LightUIFrame parentFrame, final EditMode editMode) { |
if (group == null) { |
throw new IllegalArgumentException("Null Group"); |
} |
76,66 → 76,69 |
throw new IllegalArgumentException("This group isn't attached to this SQLElement, group ID: " + group.getId() + " element code: " + sqlElement.getCode()); |
} |
final LightEditFrame editFrame = new LightEditFrame(this.configuration, group, defaultRow, parentFrame, editMode); |
final LightEditFrame editFrame = new LightEditFrame(this.configuration, group, defaultRow.asRowValues(), parentFrame, editMode); |
final LightUIPanel framePanel = editFrame.getFirstChild(LightUIPanel.class); |
append(framePanel, group); |
append(sqlElement, framePanel, group); |
String frameTitle = TranslationManager.getInstance().getTranslationForItem(group.getId()); |
if (frameTitle == null) { |
frameTitle = group.getId(); |
} |
editFrame.setTitle(frameTitle); |
editFrame.createTitlePanel(frameTitle); |
Log.get().warning("No translation for " + group.getId()); |
return editFrame; |
} |
private void append(final LightUIPanel panel, final Item item) { |
private void append(final SQLElement sqlElement, final LightUIPanel panel, final Item item) { |
if (item instanceof Group) { |
final Group gr = (Group) item; |
int size = gr.getSize(); |
final String groupTitle = TranslationManager.getInstance().getTranslationForItem(gr.getId()); |
final LightUIPanel childPanel = new LightUIPanel(gr.getId()); |
childPanel.setFillWidth(true); |
childPanel.setGridWidth(4); |
if (gr.getLocalHint().isFoldable()) { |
final LightUIPanel childPanel = new LightUIPanel(gr.getId()); |
childPanel.setTitle(groupTitle); |
childPanel.setFoldable(true); |
childPanel.setGridWidth(4); |
childPanel.setFillWidth(true); |
for (int i = 0; i < size; i++) { |
this.append(childPanel, gr.getItem(i)); |
} |
if (this.modifers.containsKey(gr.getId())) { |
this.modifers.get(gr.getId()).process(childPanel); |
} |
final LightUILine line = new LightUILine(); |
line.addChild(childPanel); |
panel.addChild(line); |
} else { |
if (groupTitle != null) { |
final LightUILine titleLine = new LightUILine(); |
final LightUILabel titleLabel = new LightUILabel(gr.getId() + ".title.label"); |
titleLabel.setGridWidth(4); |
titleLabel.setFontBold(true); |
titleLabel.setLabel(groupTitle); |
titleLabel.setFillWidth(true); |
titleLine.addChild(titleLabel); |
panel.addChild(titleLine); |
childPanel.addChild(titleLine); |
final LightUILine line = new LightUILine(); |
panel.addChild(line); |
childPanel.addChild(line); |
} |
for (int i = 0; i < size; i++) { |
final Item it = gr.getItem(i); |
this.append(panel, it); |
} |
} |
for (int i = 0; i < size; i++) { |
this.append(sqlElement, childPanel, gr.getItem(i)); |
} |
final LightUILine line = new LightUILine(); |
line.addChild(childPanel); |
panel.addChild(line); |
} else { |
final LayoutHints localHint = item.getLocalHint(); |
LightUILine currentLine = panel.getLastLine(); |
if (currentLine.getTotalGridWidth() >= 4) { |
currentLine = new LightUILine(); |
panel.addChild(currentLine); |
} |
currentLine.setMarginTop(1); |
currentLine.setMarginBottom(1); |
if (localHint.isSeparated()) { |
if (currentLine.getWidth() > 0) { |
if (currentLine.getChildrenCount() > 0) { |
currentLine = new LightUILine(); |
panel.addChild(currentLine); |
} |
148,7 → 151,7 |
currentLine.setWeightY(1); |
} |
if (currentLine.getWidth() >= this.maxColumnCount) { |
if (currentLine.getChildrenCount() >= this.maxColumnCount) { |
currentLine = new LightUILine(); |
panel.addChild(currentLine); |
} |
155,28 → 158,21 |
final SQLField field = this.mapper.getSQLFieldForItem(item.getId()); |
LightUILabel elementLabel = null; |
String label = this.getLabelForItem(field, item); |
if (label == null) { |
label = item.getId(); |
Log.get().warning("No translation for " + item.getId()); |
} |
if (localHint.showLabel()) { |
currentLine.setElementPadding(5); |
elementLabel = new LightUILabel(item.getId() + ".label"); |
elementLabel.setHorizontalAlignement(LightUIElement.HALIGN_RIGHT); |
String label = TranslationManager.getInstance().getTranslationForItem(item.getId()); |
if (label == null && field != null) { |
final RowItemDesc desc = this.configuration.getTranslator().getDescFor(field.getTable(), field.getName()); |
if (desc != null) { |
label = desc.getLabel(); |
} |
} |
if (label == null) { |
label = item.getId(); |
elementLabel.setBackgroundColor(Color.ORANGE); |
elementLabel.setToolTip("No translation for " + item.getId()); |
Log.get().warning("No translation for " + item.getId()); |
} |
elementLabel.setLabel(label); |
elementLabel.setWeightX(0); |
if (localHint.isSplit()) { |
elementLabel.setHorizontalAlignement(LightUIElement.HALIGN_LEFT); |
if (currentLine.getChildrenCount() != 0) { |
195,8 → 191,9 |
if (field != null) { |
Class<?> javaType = field.getType().getJavaType(); |
if (field.isKey()) { |
elementEditor = new LightUIComboBox(item.getId()); |
elementEditor = new LightAutoCompleteComboBox(item.getId()); |
elementEditor.setMinInputSize(20); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_REF); |
} else if (javaType.equals(String.class)) { |
if (field.getType().getSize() > 1000) { |
elementEditor = new LightUITextArea(item.getId()); |
207,15 → 204,24 |
elementEditor.setValue(""); |
elementEditor.setMinInputSize(10); |
} |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_STRING); |
} else if (javaType.equals(Boolean.class)) { |
elementEditor = new LightUICheckBox(item.getId(), ""); |
elementEditor.setLabel(label); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_BOOLEAN); |
elementLabel.setLabel(""); |
} else if (javaType.equals(Date.class)) { |
elementEditor = new LightUIDate(item.getId()); |
} else if (javaType.equals(Boolean.class)) { |
elementEditor = new LightUICheckBox(item.getId(), ""); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_DATE); |
} else if (javaType.equals(Timestamp.class)) { |
elementEditor = new LightUIDate(item.getId()); |
} else if (javaType.equals(Integer.class)) { |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_DATE); |
} else if (javaType.equals(Integer.class) || javaType.equals(Long.class) || javaType.equals(Short.class) || javaType.equals(BigInteger.class)) { |
elementEditor = new LightUITextField(item.getId()); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_INTEGER); |
} else if (javaType.equals(BigDecimal.class) || javaType.equals(Float.class) || javaType.equals(Double.class)) { |
elementEditor = new LightUITextField(item.getId()); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_DECIMAL); |
} else { |
elementEditor = new LightUITextField(item.getId()); |
Log.get().warning("unsupported type " + javaType.getName()); |
225,6 → 231,7 |
elementEditor = new LightUITextField(item.getId()); |
elementEditor.setMinInputSize(10); |
elementEditor.setToolTip("No field attached to " + item.getId()); |
elementEditor.setValueType(LightUIElement.VALUE_TYPE_STRING); |
Log.get().warning("No field attached to " + item.getId()); |
if (elementLabel != null) { |
elementLabel.setBackgroundColor(Color.ORANGE); |
235,12 → 242,10 |
if (elementEditor != null) { |
elementEditor.setWeightX(1); |
if (this.modifers.containsKey(item.getId())) { |
this.modifers.get(item.getId()).process(elementEditor); |
} |
} |
if (localHint.isSplit()) { |
if (currentLine.getWidth() > 0) { |
if (currentLine.getTotalGridWidth() > 0) { |
currentLine = new LightUILine(); |
panel.addChild(currentLine); |
} |
259,11 → 264,24 |
elementEditor.setGridWidth(1); |
} |
elementEditor.setFillWidth(localHint.fillWidth()); |
elementEditor.setMarginBottom(4); |
currentLine.addChild(elementEditor); |
} |
} |
private String getLabelForItem(final SQLField field, final Item item) { |
String label = TranslationManager.getInstance().getTranslationForItem(item.getId()); |
if (label == null && field != null) { |
final RowItemDesc desc = this.configuration.getTranslator().getDescFor(field.getTable(), field.getName()); |
if (desc != null) { |
label = desc.getLabel(); |
} |
} |
return label; |
} |
private LightUIElement getCustomEditor(final String id) { |
final CustomEditorProvider customEditorProvider = this.customEditorProviders.get(id); |
if (customEditorProvider != null) { |
283,12 → 301,4 |
public void putAllCustomEditorProvider(final Map<String, CustomEditorProvider> map) { |
this.customEditorProviders.putAll(map); |
} |
public void addModifer(final String itemId, final ConvertorModifer modifer) { |
this.modifers.put(itemId, modifer); |
} |
public void addAllModifer(final Map<String, ConvertorModifer> modifers) { |
this.modifers.putAll(modifers); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTable.java |
---|
14,211 → 14,309 |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.ListSQLRequest; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.view.list.ITableModel; |
import org.openconcerto.sql.view.list.ListSQLLine; |
import org.openconcerto.sql.view.list.SQLTableModelColumn; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline; |
import org.openconcerto.ui.SwingThreadUtils; |
import org.openconcerto.ui.light.ColumnSpec; |
import org.openconcerto.ui.light.ColumnsSpec; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.LightUITable; |
import org.openconcerto.ui.light.Row; |
import org.openconcerto.ui.light.TableContent; |
import org.openconcerto.utils.io.JSONConverter; |
import org.openconcerto.ui.light.SearchSpec; |
import org.openconcerto.utils.NumberUtils; |
import org.openconcerto.utils.cc.ITransformer; |
import java.sql.SQLException; |
import java.util.ArrayList; |
import java.util.List; |
import java.util.concurrent.Callable; |
import net.minidev.json.JSONArray; |
import javax.swing.SwingUtilities; |
import javax.swing.event.TableModelListener; |
import org.jdom2.Document; |
import org.jdom2.Element; |
import org.jdom2.input.DOMBuilder; |
import net.minidev.json.JSONObject; |
public class LightRowValuesTable extends LightUITable { |
List<SQLRowValues> listRowValues = new ArrayList<SQLRowValues>(); |
public abstract class LightRowValuesTable extends LightUITable { |
String fieldRefName; |
private SQLRowAccessor refRow; |
private boolean autoCommit = false; |
private List<Integer> deletedIds = new ArrayList<Integer>(); |
public static final int MAX_LINE_TO_SEND = 100; |
// Init from json constructor |
public LightRowValuesTable(final JSONObject json) { |
super(json); |
this.init(); |
private int totalRowCount = -1; |
private int offset = 0; |
private ITableModel model; |
private final ITransformer<SQLSelect, SQLSelect> orginTransformer; |
private List<TableModelListener> tableModelListeners = new ArrayList<TableModelListener>(); |
public LightRowValuesTable(final Configuration configuration, final Number userId, final String id, final ITableModel model) { |
super(id); |
this.model = model; |
final ColumnsSpec columnsSpec = this.createColumnsSpecFromModelSource(configuration, userId); |
this.getTableSpec().setColumns(columnsSpec); |
if (model.getReq() instanceof SQLTableModelSourceOnline) { |
final SQLTableModelSourceOnline source = (SQLTableModelSourceOnline) model.getReq(); |
this.orginTransformer = source.getReq().getSelectTransf(); |
} else { |
this.orginTransformer = null; |
} |
this.setDynamicLoad(true); |
} |
// Clone constructor |
public LightRowValuesTable(final LightRowValuesTable tableElement) { |
super(tableElement); |
this.listRowValues = tableElement.listRowValues; |
this.fieldRefName = tableElement.fieldRefName; |
this.deletedIds = tableElement.deletedIds; |
this.init(); |
this.model = tableElement.model; |
this.totalRowCount = tableElement.totalRowCount; |
this.orginTransformer = tableElement.orginTransformer; |
} |
public LightRowValuesTable(final LightUITable table, final String fieldRefName) { |
super(table); |
this.fieldRefName = fieldRefName; |
this.init(); |
// Json constructor |
public LightRowValuesTable(final JSONObject json) { |
super(json); |
this.orginTransformer = null; |
} |
public String getFieldRefName() { |
return this.fieldRefName; |
public final int getTotalRowsCount() { |
return this.totalRowCount; |
} |
public SQLRowValues getRowValues(final int index) { |
return this.listRowValues.get(index); |
public final int getOffset() { |
return this.offset; |
} |
public int getRowValuesCount() { |
return this.listRowValues.size(); |
public final void setOffset(final int offset) { |
this.offset = offset; |
} |
public boolean isAutoCommit() { |
return this.autoCommit; |
public final void addTableModelListener(final TableModelListener tableModelListener) { |
this.tableModelListeners.add(tableModelListener); |
this.model.addTableModelListener(tableModelListener); |
} |
public void setAutoCommit(boolean autoCommit) { |
if (autoCommit) { |
if (this.refRow == null) { |
throw new IllegalArgumentException("Set parent row before put this table in auto commit mode"); |
} |
} |
this.autoCommit = autoCommit; |
public final void removeTableModelListener(final TableModelListener tableModelListener) { |
this.tableModelListeners.remove(tableModelListener); |
this.model.removeTableModelListener(tableModelListener); |
} |
/** |
* Permet de charger les lignes et de lier les nouvelles lignes |
* |
*/ |
public void setParentSQLRow(final Configuration configuration, final SQLElement sqlElement, final SQLRowAccessor sqlRow) { |
public ITableModel getModel() { |
return this.model; |
} |
final TableContent content = new TableContent(getId()); |
content.setRows(new ArrayList<Row>()); |
getTableSpec().setContent(content); |
this.refRow = sqlRow; |
this.refetchTable(configuration, sqlElement); |
public final LightListSqlRow getRowFromSqlID(final Number sqlID) { |
if (this.hasRow()) { |
final int size = this.getTableSpec().getContent().getRowsCount(); |
for (int i = 0; i < size; i++) { |
final LightListSqlRow row = (LightListSqlRow) this.getRow(i); |
if (NumberUtils.areNumericallyEqual(row.getSqlRow().getIDNumber(), sqlID)) { |
return row; |
} |
} |
} |
return null; |
} |
public void refetchTable(final Configuration configuration, final SQLElement sqlElement) { |
this.getTableSpec().getContent().getRows().clear(); |
this.listRowValues.clear(); |
if (this.refRow != null && !this.refRow.isUndefined()) { |
final SQLTableModelSourceOnline tableSource = sqlElement.getTableSource(true); |
public final LightListSqlRow createLightListRowFromListLine(final ListSQLLine listSqlLine, final int index) throws IllegalStateException { |
final ColumnsSpec columnsSpec = this.getTableSpec().getColumns(); |
final List<SQLTableModelColumn> sqlColumns = this.getModelColumns(); |
final int colSize = sqlColumns.size(); |
final ListSQLRequest req = tableSource.getReq(); |
req.setWhere(new Where(sqlElement.getTable().getField(getFieldRefName()), "=", this.refRow.getID())); |
List<SQLRowValues> listRowValues = req.getValues(); |
final LightListSqlRow row = new LightListSqlRow(listSqlLine.getRow(), listSqlLine.getID()); |
final List<Object> values = new ArrayList<Object>(); |
for (int i = 0; i < colSize; i++) { |
final String columnId = columnsSpec.getColumn(i).getId(); |
final SQLTableModelColumn col = getColumnFromId(sqlColumns, columnId); |
for (final SQLRowValues rowValues : listRowValues) { |
this.addRowValues(configuration, rowValues); |
if (col != null) { |
Object value = col.show(row.getSqlRow()); |
if (col.getLightUIrenderer() != null) { |
value = col.getLightUIrenderer().getLightUIElement(value, 0, i); |
} |
values.add(value); |
} else { |
throw new IllegalArgumentException("column " + columnId + " is in ColumnsSpec but it is not found in SQLTableModelColumn"); |
} |
} |
row.setValues(values); |
return row; |
} |
public SQLRowAccessor getRefRow() { |
return this.refRow; |
public final SQLRowAccessor getFirstSelectedSqlRow() { |
final List<Row> selectedRows = this.getSelectedRows(); |
if (selectedRows.isEmpty()) { |
return null; |
} else { |
return ((LightListSqlRow) selectedRows.get(0)).getSqlRow(); |
} |
} |
public void clearRowValues(){ |
this.getTableSpec().getContent().getRows().clear(); |
this.listRowValues.clear(); |
private final List<SQLTableModelColumn> getModelColumns() { |
try { |
// TODO: clean swing |
return SwingThreadUtils.call(new Callable<List<SQLTableModelColumn>>() { |
@Override |
public List<SQLTableModelColumn> call() throws Exception { |
return LightRowValuesTable.this.getModel().getReq().getColumns(); |
} |
}); |
} catch (final Exception ex) { |
throw new IllegalStateException(ex); |
} |
} |
public void removeRowValuesAt(int index) { |
final TableContent content = this.getTableSpec().getContent(); |
content.getRows().remove(index); |
this.listRowValues.remove(index); |
private final SQLTableModelColumn getColumnFromId(final List<SQLTableModelColumn> allCols, final String columnId) { |
final int columnSize = allCols.size(); |
for (int i = 0; i < columnSize; i++) { |
final SQLTableModelColumn tableModelColumn = allCols.get(i); |
if (tableModelColumn.getIdentifier().equals(columnId)) { |
return tableModelColumn; |
} |
} |
return null; |
} |
public void addRowValues(final Configuration configuration, final SQLRowValues rowValues) { |
final TableContent content = this.getTableSpec().getContent(); |
this.listRowValues.add(rowValues); |
/** |
* Get columns user preferences for a specific table |
* |
* @param configuration - The user SQL configuration |
* @param userId - Id of the user who want view the table |
* |
* @return the XML which contains user preferences |
* |
* @throws IllegalArgumentException |
* @throws IllegalStateException |
* |
*/ |
// TODO: move in LightUITable, maybe move LightUITable in FrameWork_SQL |
private final Document getColumnsSpecUserPerfs(final Configuration configuration, final Number userId) throws IllegalArgumentException, IllegalStateException { |
Document columnsPrefs = null; |
final DOMBuilder in = new DOMBuilder(); |
org.w3c.dom.Document w3cDoc = null; |
content.getRows().add(this.createRowFromRowValues(configuration, rowValues, this.listRowValues.size() - 1)); |
w3cDoc = configuration.getXMLConf(userId, this.getId()); |
if (w3cDoc != null) { |
columnsPrefs = in.build(w3cDoc); |
} |
return columnsPrefs; |
} |
public void setRowValues(final Configuration configuration, final SQLRowValues rowValues, final int index) { |
final TableContent content = this.getTableSpec().getContent(); |
this.listRowValues.set(index, rowValues); |
content.getRows().set(index, this.createRowFromRowValues(configuration, rowValues, index)); |
} |
/** |
* Create ColumnsSpec from list of SQLTableModelColumn and apply user preferences |
* |
* @param configuration - current SQL configuration of user |
* @param userId - Id of user |
* |
* @return New ColumnsSpec with user preferences application |
* |
* @throws IllegalArgumentException |
* @throws IllegalStateException |
*/ |
private final ColumnsSpec createColumnsSpecFromModelSource(final Configuration configuration, final Number userId) throws IllegalArgumentException, IllegalStateException { |
final List<String> possibleColumnIds = new ArrayList<String>(); |
final List<String> sortedIds = new ArrayList<String>(); |
final List<ColumnSpec> columnsSpec = new ArrayList<ColumnSpec>(); |
public void archiveDeletedRows(final Configuration configuration) { |
final SQLElement sqlElement = configuration.getDirectory().getElementForCode(this.getElementCode()); |
for (final Integer deletedId : this.deletedIds) { |
try { |
sqlElement.archive(deletedId); |
} catch (final SQLException ex) { |
throw new IllegalArgumentException(ex.getMessage(), ex); |
final List<SQLTableModelColumn> columns = this.getModelColumns(); |
final int columnsCount = columns.size(); |
for (int i = 0; i < columnsCount; i++) { |
final SQLTableModelColumn sqlColumn = columns.get(i); |
// TODO : creer la notion d'ID un peu plus dans le l'esprit sales.invoice.amount |
final String columnId = sqlColumn.getIdentifier(); |
possibleColumnIds.add(columnId); |
Class<?> valueClass = sqlColumn.getValueClass(); |
if (sqlColumn.getLightUIrenderer() != null) { |
valueClass = LightUIElement.class; |
} |
} |
} |
public void addDeletedId(final int idToDelete) { |
this.deletedIds.add(idToDelete); |
} |
protected Row createRowFromRowValues(final Configuration configuration, final SQLRowValues sqlRow, final int index) { |
final SQLElement element = configuration.getDirectory().getElementForCode(this.getElementCode()); |
if (element == null) { |
throw new IllegalArgumentException("Unable to find element for code: " + this.getElementCode()); |
columnsSpec.add(new ColumnSpec(columnId, valueClass, sqlColumn.getName(), null, false, null)); |
} |
final SQLTableModelSourceOnline tableSource = element.getTableSource(true); |
final List<SQLTableModelColumn> allCols = tableSource.getColumns(); |
// TODO : recuperer l'info sauvegardée sur le serveur par user (à coder) |
sortedIds.add(columnsSpec.get(0).getId()); |
final Row row = element.createRowFromSQLRow(sqlRow, allCols, this.getTableSpec().getColumns()); |
row.setId(index); |
return row; |
} |
final ColumnsSpec cSpec = new ColumnsSpec(this.getId(), columnsSpec, possibleColumnIds, sortedIds); |
cSpec.setAllowMove(true); |
cSpec.setAllowResize(true); |
private void init() { |
if (this.getTableSpec().getContent() == null) { |
this.getTableSpec().setContent(new TableContent(this.getId())); |
final Document xmlColumnsPref = this.getColumnsSpecUserPerfs(configuration, userId); |
if (!cSpec.setUserPrefs(xmlColumnsPref)) { |
configuration.removeXMLConf(userId, this.getId()); |
} |
return cSpec; |
} |
// TODO: merge with OpenConcerto List search system |
public abstract void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset); |
@Override |
public LightUIElement clone() { |
return new LightRowValuesTable(this); |
public Row getRowById(Number rowId) { |
for (int i = 0; i < this.model.getRowCount(); i++) { |
if (NumberUtils.areNumericallyEqual(this.model.getRow(i).getID(), rowId)) { |
return this.createLightListRowFromListLine(this.model.getRow(i), i); |
} |
} |
return super.getRowById(rowId); |
} |
/** |
* Create default columns preferences from the SQLTableModelLinesSourceOnline |
* |
* @return XML document with columns preferences |
*/ |
@Override |
public JSONObject toJSON() { |
final JSONObject json = super.toJSON(); |
public Document createDefaultXmlPreferences() { |
final Element rootElement = new Element("list"); |
final List<SQLTableModelColumn> columns = this.getModelColumns(); |
// TODO: implement row values JSONAble |
if (this.listRowValues != null && !this.listRowValues.isEmpty()) { |
json.put("list-row-values", null); |
final int sqlColumnsCount = columns.size(); |
for (int i = 0; i < sqlColumnsCount; i++) { |
final SQLTableModelColumn sqlColumn = columns.get(i); |
final String columnId = sqlColumn.getIdentifier(); |
final ColumnSpec columnSpec = new ColumnSpec(columnId, sqlColumn.getValueClass(), sqlColumn.getName(), null, false, null); |
final Element columnElement = this.createXmlColumn(columnId, columnSpec.getMaxWidth(), columnSpec.getMinWidth(), columnSpec.getWidth()); |
rootElement.addContent(columnElement); |
} |
if (this.deletedIds != null && !this.deletedIds.isEmpty()) { |
json.put("deleted-ids", JSONConverter.getJSON(this.deletedIds)); |
} |
final Document xmlConf = new Document(rootElement); |
return json; |
return xmlConf; |
} |
@Override |
public void fromJSON(final JSONObject json) { |
super.fromJSON(json); |
final JSONArray jsonListRowValues = JSONConverter.getParameterFromJSON(json, "list-row-values", JSONArray.class); |
this.listRowValues = new ArrayList<SQLRowValues>(); |
// TODO: implement row values JSONAble |
if (jsonListRowValues != null) { |
} |
public void destroy() { |
super.destroy(); |
if (this.getTableSpec().getContent() != null) { |
this.getTableSpec().getContent().getRows().clear(); |
// TODO: clean swing |
try { |
SwingUtilities.invokeAndWait(new Runnable() { |
@Override |
public void run() { |
final List<TableModelListener> tableModelListeners = LightRowValuesTable.this.tableModelListeners; |
for (int i = tableModelListeners.size() - 1; i > -1; i--) { |
LightRowValuesTable.this.removeTableModelListener(tableModelListeners.get(i)); |
} |
} |
}); |
} catch (final Exception ex) { |
throw new IllegalStateException(ex); |
} |
final JSONArray jsonDeletedIds = JSONConverter.getParameterFromJSON(json, "deleted-ids", JSONArray.class); |
this.deletedIds = new ArrayList<Integer>(); |
if (jsonDeletedIds != null) { |
for (final Object jsonDeletedId : jsonDeletedIds) { |
this.deletedIds.add(JSONConverter.getObjectFromJSON(jsonDeletedId, Integer.class)); |
} |
} |
this.clearRows(); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightEditFrame.java |
---|
20,12 → 20,12 |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLRowValuesListFetcher; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.view.EditPanel.EditMode; |
import org.openconcerto.sql.view.list.ListSQLLine; |
import org.openconcerto.sql.view.list.SQLTableModelLinesSourceOffline; |
import org.openconcerto.ui.group.Group; |
import org.openconcerto.ui.group.Item; |
import org.openconcerto.ui.light.ComboValueConvertor; |
import org.openconcerto.ui.light.CustomEditorProvider; |
import org.openconcerto.ui.light.JSONToLightUIConvertor; |
import org.openconcerto.ui.light.LightUICheckBox; |
33,13 → 33,14 |
import org.openconcerto.ui.light.LightUIDate; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.LightUIFrame; |
import org.openconcerto.ui.light.StringValueConvertor; |
import org.openconcerto.utils.io.JSONConverter; |
import java.math.BigDecimal; |
import java.sql.SQLException; |
import java.sql.Timestamp; |
import java.util.Date; |
import java.util.Map; |
import java.util.concurrent.Future; |
import net.minidev.json.JSONObject; |
87,10 → 88,13 |
/** |
* Commit the SQLRowValues attached to this frame |
* |
* @param configuration Current configuration |
* @param configuration - Current configuration |
* |
* @return The inserted SQLRow |
* |
* @throws SQLException When an error occur in SQLRowValues.commit() |
*/ |
public SQLRow commitSqlRow(final Configuration configuration) { |
public SQLRow commitSqlRow(final Configuration configuration) throws SQLException { |
if (this.editMode.equals(EditMode.READONLY)) { |
throw new IllegalArgumentException("Impossible to commit values when the frame is read only"); |
} |
98,7 → 102,7 |
try { |
return this.sqlRow.prune(sqlElement.getPrivateGraph()).commit(); |
} catch (final SQLException ex) { |
throw new IllegalArgumentException("Unable to commit SQLRowValues, edit frame ID: " + this.getId()); |
throw ex; |
} |
} |
120,14 → 124,14 |
* @param conf |
* @param userId |
*/ |
public void updateRow(final Configuration configuration, final int userId) { |
public void updateRow(final Configuration configuration, final String sessionSecurityToken, final int userId) { |
if (this.editMode.equals(EditMode.READONLY)) { |
throw new IllegalArgumentException("Impossible to update values when the frame is read only"); |
} |
this.updateRow(configuration, this.group, userId); |
this.updateRow(configuration, this.group, sessionSecurityToken, userId); |
} |
private void updateRow(final Configuration configuration, final Group group, final int userId) { |
private void updateRow(final Configuration configuration, final Group group, final String sessionSecurityToken, final int userId) { |
final FieldMapper fieldMapper = configuration.getFieldMapper(); |
if (fieldMapper == null) { |
throw new IllegalStateException("null field mapper"); |
134,26 → 138,25 |
} |
final SQLElement sqlElement = configuration.getDirectory().getElement(this.sqlRow.getTable()); |
final Map<String, ComboValueConvertor<?>> valueConvertors = sqlElement.getComboConvertors(); |
Map<String, CustomEditorProvider> customEditors = null; |
final Map<String, CustomEditorProvider> customEditors; |
if (this.editMode.equals(EditMode.CREATION)) { |
customEditors = sqlElement.getCustomEditorProviderForCreation(configuration, userId); |
customEditors = sqlElement.getCustomEditorProviderForCreation(configuration, sessionSecurityToken); |
} else { |
customEditors = sqlElement.getCustomEditorProviderForModification(configuration, this.sqlRow, userId); |
customEditors = sqlElement.getCustomEditorProviderForModification(configuration, this.sqlRow, sessionSecurityToken); |
} |
this.createRowValues(configuration, fieldMapper, this.group, valueConvertors, customEditors); |
this.createRowValues(configuration, sqlElement, fieldMapper, this.group, customEditors); |
this.setMetaData(userId); |
} |
final protected void createRowValues(final Configuration conf, final FieldMapper fieldMapper, final Group group, final Map<String, ComboValueConvertor<?>> valueConvertors, |
final protected void createRowValues(final Configuration configuration, final SQLElement sqlElement, final FieldMapper fieldMapper, final Group group, |
final Map<String, CustomEditorProvider> customEditors) { |
final int itemCount = group.getSize(); |
for (int i = 0; i < itemCount; i++) { |
final Item item = group.getItem(i); |
if (item instanceof Group) { |
this.createRowValues(conf, fieldMapper, (Group) item, valueConvertors, customEditors); |
this.createRowValues(configuration, sqlElement, fieldMapper, (Group) item, customEditors); |
} else { |
final SQLField field = fieldMapper.getSQLFieldForItem(item.getId()); |
if (field != null) { |
163,26 → 166,8 |
throw new IllegalArgumentException("Impossible to find UI Element with id: " + item.getId()); |
} |
if (!valueConvertors.containsKey(item.getId()) && !customEditors.containsKey(item.getId())) { |
this.putValueFromUserControl(conf, field, uiElement); |
} else if (valueConvertors.containsKey(item.getId())) { |
if (!(uiElement instanceof LightUIComboBox)) { |
throw new IllegalArgumentException("The UI Element with ID " + item.getId() + ", must be an instance of LightUIComboBox"); |
} |
final LightUIComboBox combo = (LightUIComboBox) uiElement; |
if (combo.hasSelectedValue() && combo.getSelectedValue().getId() != 0) { |
final ComboValueConvertor<?> valueConvertor = valueConvertors.get(item.getId()); |
if (valueConvertor instanceof StringValueConvertor) { |
this.sqlRow.put(field.getFieldName(), ((StringValueConvertor) valueConvertor).getIdFromIndex(combo.getSelectedValue().getId())); |
} else { |
final int selectedId = combo.getSelectedValue().getId(); |
this.sqlRow.put(field.getFieldName(), selectedId); |
} |
} else { |
this.sqlRow.put(field.getFieldName(), null); |
} |
} else if (customEditors.containsKey(item.getId())) { |
Log.get().warning("Unable to save value of element: " + item.getId()); |
if (!uiElement.isNotSaved()) { |
this.putValueFromUserControl(configuration, sqlElement, field, uiElement, customEditors); |
} |
} else { |
Log.get().warning("No field attached to " + item.getId()); |
191,57 → 176,77 |
} |
} |
final protected void putValueFromUserControl(final Configuration conf, final SQLField field, final LightUIElement uiElement) { |
final Class<?> fieldType = field.getType().getJavaType(); |
if (field.isKey()) { |
if (!(uiElement instanceof LightUIComboBox)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + field.getName() + ". When field is foreign key, UI Element must be a LightUIDate"); |
} |
final LightUIComboBox combo = (LightUIComboBox) uiElement; |
final protected void putValueFromUserControl(final Configuration configuration, final SQLElement sqlElement, final SQLField sqlField, final LightUIElement uiElement, |
final Map<String, CustomEditorProvider> customEditors) { |
if (!uiElement.isNotSaved()) { |
final Class<?> fieldType = sqlField.getType().getJavaType(); |
if (customEditors.containsKey(uiElement.getId())) { |
final CustomEditorProvider customEditor = customEditors.get(uiElement.getId()); |
if (customEditor instanceof SavableCustomEditorProvider) { |
((SavableCustomEditorProvider) customEditor).save(this.sqlRow, sqlField, uiElement); |
} |
} else { |
final String fieldName = sqlField.getFieldName(); |
if (sqlField.isKey()) { |
if (!(uiElement instanceof LightUIComboBox)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + fieldName + ". When field is foreign key, UI Element must be a LightUIDate"); |
} |
final LightUIComboBox combo = (LightUIComboBox) uiElement; |
if (combo.hasSelectedValue()) { |
final SQLRowValues tmp = new SQLRowValues(this.sqlRow.getTable()).put(field.getName(), null); |
conf.getDirectory().getShowAs().expand(tmp); |
final SQLRowValues toFetch = (SQLRowValues) tmp.getForeign(field.getName()); |
tmp.remove(field.getName()); |
if (combo.hasSelectedValue()) { |
this.sqlRow.put(fieldName, combo.getSelectedValue().getId()); |
} else { |
this.sqlRow.put(fieldName, null); |
} |
} else { |
final String value = uiElement.getValue(); |
if (value == null && !sqlField.isNullable()) { |
Log.get().warning("ignoring null value for not nullable field " + fieldName + " from table " + sqlField.getTable().getName()); |
} else { |
if (fieldType.equals(String.class)) { |
// FIXME check string size against field size |
this.sqlRow.put(fieldName, value); |
} else if (fieldType.equals(Date.class)) { |
if (!(uiElement instanceof LightUIDate)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + fieldName + ". When field is Date, UI Element must be a LightUIDate"); |
} |
this.sqlRow.put(fieldName, ((LightUIDate) uiElement).getValueAsDate()); |
} else if (fieldType.equals(Boolean.class)) { |
if (!(uiElement instanceof LightUICheckBox)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + fieldName + ". When field is Boolean, UI Element must be a LightUICheckBox"); |
} |
this.sqlRow.put(fieldName, ((LightUICheckBox) uiElement).isChecked()); |
} else if (fieldType.equals(Timestamp.class)) { |
if (!(uiElement instanceof LightUIDate)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + fieldName + ". When field is Date, UI Element must be a LightUIDate"); |
} |
this.sqlRow.put(fieldName, ((LightUIDate) uiElement).getValueAsDate()); |
} else if (fieldType.equals(Integer.class)) { |
if (value != null && !value.trim().isEmpty()) { |
if (!value.matches("^-?\\d+$")) { |
throw new IllegalArgumentException("Invalid value for field: " + fieldName + " value: " + value); |
} |
this.sqlRow.put(fieldName, Integer.parseInt(value)); |
} else { |
this.sqlRow.put(fieldName, null); |
} |
} else if (fieldType.equals(Double.class) || fieldType.equals(Float.class) || fieldType.equals(BigDecimal.class)) { |
if (value != null && !value.trim().isEmpty()) { |
try { |
this.sqlRow.put(fieldName, new BigDecimal(value)); |
} catch (final Exception ex) { |
throw new IllegalArgumentException("Invalid value for field: " + fieldName + " value: " + value); |
} |
final SQLRowValues fetched = SQLRowValuesListFetcher.create(toFetch).fetchOne(combo.getSelectedValue().getId()); |
if (fetched == null) { |
throw new IllegalArgumentException("Impossible to find Row in database - table: " + field.getForeignTable().getName() + ", id: " + combo.getSelectedValue().getId()); |
} else { |
this.sqlRow.put(fieldName, null); |
} |
} else { |
Log.get().warning("unsupported type " + fieldName); |
} |
} |
} |
this.sqlRow.put(field.getFieldName(), fetched); |
} else { |
this.sqlRow.put(field.getFieldName(), null); |
} |
} else if (fieldType.equals(String.class)) { |
this.sqlRow.put(field.getFieldName(), uiElement.getValue()); |
} else if (fieldType.equals(Date.class)) { |
if (!(uiElement instanceof LightUIDate)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + field.getName() + ". When field is Date, UI Element must be a LightUIDate"); |
} |
this.sqlRow.put(field.getFieldName(), ((LightUIDate) uiElement).getValueAsDate()); |
} else if (fieldType.equals(Boolean.class)) { |
if (!(uiElement instanceof LightUICheckBox)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + field.getName() + ". When field is Boolean, UI Element must be a LightUICheckBox"); |
} |
this.sqlRow.put(field.getFieldName(), ((LightUICheckBox) uiElement).isChecked()); |
} else if (fieldType.equals(Timestamp.class)) { |
if (!(uiElement instanceof LightUIDate)) { |
throw new IllegalArgumentException("Invalid UI Element for field: " + field.getName() + ". When field is Date, UI Element must be a LightUIDate"); |
} |
this.sqlRow.put(field.getFieldName(), ((LightUIDate) uiElement).getValueAsDate()); |
} else if (fieldType.equals(Integer.class)) { |
if (uiElement.getValue() != null && !uiElement.getValue().trim().isEmpty()) { |
if (!uiElement.getValue().matches("^-?\\d+$")) { |
throw new IllegalArgumentException("Invalid value for field: " + field.getName() + " value: " + uiElement.getValue()); |
} |
this.sqlRow.put(field.getFieldName(), Integer.parseInt(uiElement.getValue())); |
} else { |
this.sqlRow.put(field.getFieldName(), null); |
} |
} else { |
Log.get().warning("unsupported type " + fieldType.getName()); |
} |
} |
253,37 → 258,33 |
* @param row Element saved row |
* @param customEditors List of custom editors used in element edit frame |
*/ |
final public void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors) { |
this.saveReferentRows(configuration, this.group, parentSqlRow, customEditors); |
final public void saveReferentRows(final Configuration configuration, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, final String sessionSecurityToken) { |
this.saveReferentRows(configuration, this.group, parentSqlRow, customEditors, sessionSecurityToken); |
} |
final private void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors) { |
final private void saveReferentRows(final Configuration configuration, final Group group, final SQLRow parentSqlRow, final Map<String, CustomEditorProvider> customEditors, |
final String sessionSecurityToken) { |
for (int i = 0; i < group.getSize(); i++) { |
final Item item = group.getItem(i); |
if (item instanceof Group) { |
this.saveReferentRows(configuration, (Group) item, parentSqlRow, customEditors); |
this.saveReferentRows(configuration, (Group) item, parentSqlRow, customEditors, sessionSecurityToken); |
} else if (customEditors.containsKey(item.getId())) { |
final LightUIElement element = this.findChild(item.getId(), false); |
if (element instanceof LightRowValuesTable) { |
final LightRowValuesTable rowValsTable = (LightRowValuesTable) element; |
final int rowValuesCount = rowValsTable.getRowValuesCount(); |
for (int j = 0; j < rowValuesCount; j++) { |
SQLRowValues rowValues = rowValsTable.getRowValues(j); |
if (!rowValues.isFrozen()) { |
rowValues.put(rowValsTable.getFieldRefName(), parentSqlRow.getID()); |
try { |
final SQLElement el = configuration.getDirectory().getElement(rowValues.getTable()); |
boolean insertion = !rowValues.hasID(); |
SQLRow rowInserted = rowValues.prune(el.getPrivateGraph()).commit(); |
if (insertion) { |
((SQLElement) el).doAfterLightInsert(rowInserted); |
} |
} catch (SQLException e) { |
throw new IllegalArgumentException(e.getMessage(), e); |
} |
} |
if (element instanceof LightForeignRowValuesTableOffline) { |
final LightForeignRowValuesTableOffline foreignTable = (LightForeignRowValuesTableOffline) element; |
for (int j = 0; j < foreignTable.getRowsCount(); j++) { |
final ListSQLLine listLine = foreignTable.getModel().getRow(j); |
final SQLRowValues rowVals = listLine.getRow().createEmptyUpdateRow(); |
rowVals.put(foreignTable.getForeignField().getName(), parentSqlRow.getID()); |
((SQLTableModelLinesSourceOffline) foreignTable.getModel().getLinesSource()).updateRow(listLine.getID(), rowVals); |
} |
rowValsTable.archiveDeletedRows(configuration); |
final Future<?> fCommit = foreignTable.commitRows(); |
try { |
fCommit.get(); |
} catch (final Exception ex) { |
throw new IllegalArgumentException(ex); |
} |
} |
} |
} |
291,7 → 292,6 |
final protected void setMetaData(final int userId) { |
final SQLTable sqlTable = this.sqlRow.getTable(); |
// FIXME: Creation user not specified. |
if (this.sqlRow.getObject(sqlTable.getCreationUserField().getName()) == null || this.sqlRow.getObject(sqlTable.getCreationDateField().getName()) == null) { |
this.sqlRow.put(sqlTable.getCreationUserField().getName(), userId); |
this.sqlRow.put(sqlTable.getCreationDateField().getName(), new Date()); |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/SavableCustomEditorProvider.java |
---|
Nouveau fichier |
0,0 → 1,31 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.ui.light.CustomEditorProvider; |
import org.openconcerto.ui.light.LightUIElement; |
public abstract class SavableCustomEditorProvider extends CustomEditorProvider { |
public final void save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) throws IllegalArgumentException, IllegalStateException { |
if (sqlRow == null || sqlField == null) { |
throw new IllegalStateException("Impossible to save this editor: " + uiElement.getId()); |
} |
this._save(sqlRow, sqlField, uiElement); |
} |
protected abstract void _save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) throws IllegalArgumentException, IllegalStateException; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightListSqlRow.java |
---|
Nouveau fichier |
0,0 → 1,30 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.ui.light.Row; |
public class LightListSqlRow extends Row { |
final private SQLRowValues sqlRow; |
public LightListSqlRow(final SQLRowValues sqlRow, final Number id) { |
super(id); |
this.sqlRow = sqlRow; |
} |
public SQLRowValues getSqlRow() { |
return this.sqlRow; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/light/LightRowValuesTableOnline.java |
---|
Nouveau fichier |
0,0 → 1,147 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.ui.light; |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLFunctionField; |
import org.openconcerto.sql.model.SQLFunctionField.SQLFunction; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.ListSQLRequest; |
import org.openconcerto.sql.view.list.ITableModel; |
import org.openconcerto.sql.view.list.SQLTableModelColumn; |
import org.openconcerto.sql.view.list.SQLTableModelSource; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline; |
import org.openconcerto.ui.light.SearchSpec; |
import org.openconcerto.utils.cc.ITransformer; |
import java.util.ArrayList; |
import java.util.HashSet; |
import java.util.List; |
import java.util.Set; |
import java.util.concurrent.Callable; |
import java.util.concurrent.FutureTask; |
import javax.swing.SwingUtilities; |
import net.minidev.json.JSONObject; |
public class LightRowValuesTableOnline extends LightRowValuesTable { |
private final ITransformer<SQLSelect, SQLSelect> orginTransformer; |
public LightRowValuesTableOnline(final Configuration configuration, final Number userId, final String id, final ITableModel model) { |
super(configuration, userId, id, model); |
this.orginTransformer = ((SQLTableModelSourceOnline) model.getReq()).getReq().getSelectTransf(); |
} |
// Clone constructor |
public LightRowValuesTableOnline(final LightRowValuesTableOnline tableElement) { |
super(tableElement); |
this.orginTransformer = tableElement.orginTransformer; |
} |
// Json constructor |
public LightRowValuesTableOnline(final JSONObject json) { |
super(json); |
this.orginTransformer = null; |
} |
@Override |
public void doSearch(final Configuration configuration, final SearchSpec searchSpec, final int offset) { |
this.getTableSpec().setSearch(searchSpec); |
this.setOffset(offset); |
final SQLTableModelSource tableSource = this.getModel().getReq(); |
final SearchInfo sInfo = (searchSpec != null) ? new SearchInfo(searchSpec) : null; |
final FutureTask<ListSQLRequest> f = new FutureTask<ListSQLRequest>(new Callable<ListSQLRequest>() { |
@Override |
public ListSQLRequest call() throws Exception { |
final ListSQLRequest req = tableSource.getReq(); |
final List<SQLTableModelColumn> columns = tableSource.getColumns(); |
req.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(final SQLSelect sel) { |
if (LightRowValuesTableOnline.this.orginTransformer != null) { |
LightRowValuesTableOnline.this.orginTransformer.transformChecked(sel); |
} |
setWhere(sel, sInfo, columns); |
return sel; |
} |
}); |
return req; |
} |
}); |
// TODO: clean swing |
SwingUtilities.invokeLater(f); |
try { |
final ListSQLRequest req = f.get(); |
// get values |
long t4 = System.currentTimeMillis(); |
final List<SQLRowValues> rowValues = req.getValues(); |
final int size = rowValues.size(); |
long t5 = System.currentTimeMillis(); |
System.err.println("DefaultTableContentHandler.handle() getValues() :" + size + " : " + (t5 - t4) + " ms"); |
} catch (final Exception e) { |
throw new IllegalStateException(e); |
} |
} |
/** |
* Apply filter on ListSQLRequest |
* |
* @param sel - The ListSQLRequest select |
* @param sInfo - Search parameters |
*/ |
private final void setWhere(final SQLSelect sel, final SearchInfo sInfo, final List<SQLTableModelColumn> cols) { |
if (sInfo != null) { |
final Set<SQLField> fields = new HashSet<SQLField>(); |
for (final SQLTableModelColumn sqlTableModelColumn : cols) { |
fields.addAll(sqlTableModelColumn.getFields()); |
} |
final List<Where> wheres = new ArrayList<Where>(); |
final List<Where> wFields = new ArrayList<Where>(); |
final List<String> texts = sInfo.getTexts(); |
for (String string : texts) { |
wFields.clear(); |
for (final SQLField sqlField : fields) { |
if (sqlField.getType().getJavaType().equals(String.class)) { |
final Where w = new Where(new SQLFunctionField(SQLFunction.LOWER, sel.getAlias(sqlField)), "LIKE", "%" + string.toLowerCase() + "%"); |
wFields.add(w); |
} |
} |
wheres.add(Where.or(wFields)); |
} |
final Where w; |
if (sel.getWhere() != null) { |
w = Where.and(sel.getWhere(), Where.and(wheres)); |
} else { |
w = Where.and(wheres); |
} |
sel.setWhere(w); |
System.err.println(sel.asString()); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ElementComboBoxUtils.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/JUniqueTextField.java |
---|
69,6 → 69,9 |
*/ |
public class JUniqueTextField extends JPanel implements ValueWrapper<String>, Documented, TextComponent, RowItemViewComponent, SQLComponentItem, MouseListener { |
public static int RETRY_COUNT = 5; |
public static int SLEEP_WAIT_MS = 200; |
public static final boolean exists(final SQLField f, final String t, final Number idToExclude, final boolean withCache) throws RTInterruptedException { |
final SQLSelect selNum = new SQLSelect(); |
selNum.addSelectFunctionStar("COUNT"); |
182,7 → 185,16 |
while (JUniqueTextField.this.loop) { |
try { |
checkValidation(false); |
if (!checkValidation(false)) { |
final String number = getAutoRefreshNumber(); |
if (number != null && number.trim().length() > 0 && !number.equals(getText())) { |
SwingUtilities.invokeLater(new Runnable() { |
public void run() { |
JUniqueTextField.this.textField.setText(number); |
} |
}); |
} |
} |
} catch (RTInterruptedException e) { |
// Arret normal si le texte a changé |
} |
200,6 → 212,15 |
this.validationThread.start(); |
} |
/** |
* Actualisation automatique du numéro si il est pris lors la vérification automatique |
* |
* @return le nouveau numéro. Par défaut null, pas d'actualisation automatique. |
*/ |
public String getAutoRefreshNumber() { |
return null; |
} |
public synchronized boolean checkValidation() throws RTInterruptedException { |
return checkValidation(true); |
} |
228,7 → 249,7 |
return false; |
} |
if (System.currentTimeMillis() - this.lastCheck < 1000) { |
if (withCache && System.currentTimeMillis() - this.lastCheck < 1000) { |
// Ne pas checker 2 fois dans la meme seconde |
// On laisse le watcher le faire |
this.waitTime = 1000; |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/IComboModel.java |
---|
20,13 → 20,17 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableEvent; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.ComboSQLRequest; |
import org.openconcerto.sql.request.ComboSQLRequest.KeepMode; |
import org.openconcerto.sql.view.list.ITableModel.SleepState; |
import org.openconcerto.sql.view.search.SearchSpec; |
import org.openconcerto.sql.view.search.SearchSpecUtils; |
import org.openconcerto.ui.SwingThreadUtils; |
import org.openconcerto.ui.component.combo.Log; |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.RTInterruptedException; |
import org.openconcerto.utils.StringUtils; |
import org.openconcerto.utils.SwingWorker2; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.checks.EmptyChangeSupport; |
41,11 → 45,15 |
import java.beans.PropertyChangeListener; |
import java.beans.PropertyChangeSupport; |
import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.Collections; |
import java.util.HashMap; |
import java.util.List; |
import java.util.Locale; |
import java.util.Map; |
import java.util.concurrent.CancellationException; |
import java.util.concurrent.ExecutionException; |
import java.util.regex.Pattern; |
import javax.swing.SwingUtilities; |
import javax.swing.event.ListDataEvent; |
66,8 → 74,8 |
private boolean filledOnce = false; |
private ITransformer<List<IComboSelectionItem>, IComboSelectionItem> firstFillTransf = null; |
private boolean isADirtyDrityGirl = true; |
private boolean isOnScreen = false; |
@GuardedBy("this") |
private boolean isADirtyDrityGirl; |
private boolean sleepAllowed = true; |
@GuardedBy("this") |
private int requestDelay = 50; |
90,15 → 98,25 |
@GuardedBy("this") |
private SearchSpec search; |
private final boolean reqSearchable; |
@GuardedBy("this") |
private List<String> searchQuery; |
@GuardedBy("this") |
private Where searchForceInclude; |
private PropertyChangeListener filterListener; |
// whether this is listening in order to self-update |
private boolean running; |
@GuardedBy("this") |
private SleepState sleepState; |
private boolean debug = false; |
private boolean addMissingItem; |
public IComboModel(final ComboSQLRequest req) { |
this(req, req.isSearchable()); |
} |
public IComboModel(final ComboSQLRequest req, final boolean reqSearchable) { |
if (req == null) |
throw new NullPointerException("null request"); |
this.req = req; |
108,6 → 126,10 |
this.idToSelect = SQLRow.NONEXISTANT_ID; |
this.search = null; |
// if req change and is no longer searchable, getComboItems() will fail |
this.reqSearchable = reqSearchable; |
this.searchQuery = Collections.emptyList(); |
this.searchForceInclude = null; |
this.runnables = new ArrayList<Runnable>(); |
this.willUpdate = null; |
this.updating = false; |
114,7 → 136,8 |
this.itemsByID = new HashMap<Integer, IComboSelectionItem>(); |
this.addMissingItem = true; |
this.running = false; |
this.sleepState = SleepState.HIBERNATING; |
this.isADirtyDrityGirl = true; |
this.setSelectOnAdd(false); |
// we always change the selection after changing the items so don't make an extra fire |
201,19 → 224,25 |
super.fireContentsChanged(source, index0, index1); |
} |
void setRunning(final boolean b) { |
synchronized void setSleepState(SleepState newState) { |
assert SwingUtilities.isEventDispatchThread(); |
if (this.running != b) { |
this.running = b; |
if (this.running) { |
if (newState == SleepState.SLEEPING && !this.isSleepAllowed()) |
newState = SleepState.AWAKE; |
final SleepState prev = this.sleepState; |
if (prev != newState) { |
this.sleepState = newState; |
if (prev == SleepState.HIBERNATING) { |
this.req.addTableListener(this); |
this.req.addWhereListener(this.filterListener); |
// since we weren't listening, we must have missed lots of things |
this.fillCombo(); |
} else { |
this.isADirtyDrityGirl = true; |
} else if (newState == SleepState.HIBERNATING) { |
this.req.removeTableListener(this); |
this.req.rmWhereListener(this.filterListener); |
} |
if (newState == SleepState.AWAKE && this.isADirtyDrityGirl) { |
this.fillCombo(); |
} |
} |
} |
230,19 → 259,6 |
Log.get().info(s); |
} |
synchronized void setOnScreen(boolean isOnScreen) { |
if (this.isOnScreen != isOnScreen) { |
this.isOnScreen = isOnScreen; |
if (this.isOnScreen && this.isADirtyDrityGirl) { |
this.fillCombo(); |
} |
} |
} |
private synchronized boolean isOnScreen() { |
return this.isOnScreen; |
} |
/** |
* Whether this combo is allowed to delay {@link #fillCombo()} when it isn't visible. |
* |
256,6 → 272,14 |
return this.sleepAllowed; |
} |
private final synchronized boolean isActive() { |
return this.sleepState == SleepState.AWAKE; |
} |
private final synchronized boolean areValuesObsolete() { |
return this.isUpdating() || !this.isActive(); |
} |
public synchronized final int getRequestDelay() { |
return this.requestDelay; |
} |
273,7 → 297,7 |
/** |
* Reload this combo. This method is thread-safe. |
*/ |
public synchronized final void fillCombo() { |
public final void fillCombo() { |
this.fillCombo(null, true); |
} |
280,7 → 304,7 |
public synchronized final void fillCombo(final Runnable r, final boolean readCache) { |
// wholly synch otherwise we might get onScreen after the if |
// and thus completely ignore that fillCombo() |
if (!this.isSleepAllowed() || this.isOnScreen() || r != null) { |
if (this.isActive() || r != null) { |
this.doUpdateAll(r, readCache); |
} else { |
this.isADirtyDrityGirl = true; |
323,6 → 347,9 |
final int delay = this.getRequestDelay(); |
// copy the current search, if it changes fillCombo() will be called |
final SearchSpec search = this.getSearch(); |
final List<String> searchQuery = this.getSearchQuery(); |
final Where searchForceInclude = this.getSearchForceInclude(); |
log("will call getComboItems(" + readCache + ", " + searchQuery + ", " + searchForceInclude + ")"); |
// commencer l'update après, sinon modeToSelect == 0 |
final SwingWorker2<List<IComboSelectionItem>, Object> worker = new SwingWorker2<List<IComboSelectionItem>, Object>() { |
330,7 → 357,7 |
protected List<IComboSelectionItem> doInBackground() throws InterruptedException { |
// attends 1 peu pour voir si on va pas être annulé |
Thread.sleep(delay); |
return SearchSpecUtils.filter(IComboModel.this.req.getComboItems(readCache), search); |
return SearchSpecUtils.filter(IComboModel.this.req.getComboItems(readCache, searchQuery, Locale.getDefault(), searchForceInclude), search); |
} |
// Runs on the event-dispatching thread. |
345,7 → 372,7 |
final boolean firstFill = !IComboModel.this.filledOnce; |
// store before removing since it can trigger a selection change |
final int idToSelect = IComboModel.this.idToSelect; |
final int idToSelect = getWantedID(); |
List<IComboSelectionItem> items = null; |
try { |
items = this.get(); |
378,6 → 405,10 |
IComboModel.this.setSelectedItem(items.get(0)); |
else if (noSelection && firstFill && getFirstFillSelection() != null) |
IComboModel.this.setSelectedItem(getFirstFillSelection().transformChecked(items)); |
// if the wanted ID has changed after we made the request, and we didn't |
// get the it, retry |
else if (!noSelection && getComboItem(idToSelect) == null && !CompareUtils.equals(getSearchForceInclude(), searchForceInclude)) |
fillCombo(); |
else |
selectID(idToSelect); |
485,15 → 516,19 |
*/ |
@Override |
public final IComboSelectionItem getValue() { |
if (!this.isUpdating()) |
return this.getSelectedValue(); |
else if (this.getWantedID() == SQLRow.NONEXISTANT_ID) |
return null; |
else if (this.getRequest().getKeepMode() == KeepMode.NONE) |
return new IComboSelectionItem(getWantedID(), null); |
else |
final IComboSelectionItem res; |
if (!areValuesObsolete()) { |
res = this.getSelectedValue(); |
} else if (this.getWantedID() == SQLRow.NONEXISTANT_ID) { |
res = null; |
} else if (this.getRequest().getKeepMode() == KeepMode.NONE) { |
res = new IComboSelectionItem(getWantedID(), null); |
} else { |
// no point in passing an SQLRowValues as the graph would be limited to just this row |
return new IComboSelectionItem(new SQLRow(this.getForeignTable(), getWantedID()), null); |
res = new IComboSelectionItem(new SQLRow(this.getForeignTable(), getWantedID()), null); |
} |
assert (this.getWantedID() != SQLRow.NONEXISTANT_ID && this.getWantedID() == res.getId()) || (this.getWantedID() == SQLRow.NONEXISTANT_ID && res == null); |
return res; |
} |
/** |
520,9 → 555,11 |
} |
private final void setWantedID(int id) { |
assert SwingUtilities.isEventDispatchThread(); |
if (this.idToSelect != id) { |
final int old = this.idToSelect; |
this.idToSelect = id; |
this.setSearchForceInclude(id); |
this.propSupp.firePropertyChange("wantedID", old, id); |
this.propSupp.firePropertyChange("value", null, getValue()); |
this.emptySupp.fireEmptyChange(this.isEmpty()); |
574,66 → 611,75 |
log("entering selectID " + id); |
assert SwingUtilities.isEventDispatchThread(); |
// no need to launch another updateAll() if one is already underway |
if (this.neverBeenFilled() && !isUpdating()) |
// don't use fillCombo() which won't really update unless we're on screen |
this.doUpdateAll(null, true); |
if (this.isUpdating()) { |
if (this.areValuesObsolete()) { |
this.setWantedID(id); |
log("isUpdating: this.idToSelect = " + id); |
// if this is updating, the wanted ID will eventually get selected, otherwise signal |
// that on a wake up we should check wantedID |
if (!this.isUpdating()) { |
synchronized (this) { |
this.isADirtyDrityGirl = true; |
} |
} |
log("values are obsolete: wantedID = " + id); |
} else if (id == SQLRow.NONEXISTANT_ID) { |
this.setSelectedItem(null); |
log("NONEXISTANT_ID: setSelectedItem(null)"); |
} else { |
final IComboSelectionItem item = this.getComboItem(id); |
log("valid id : " + id + " item: " + item); |
// * setSelectedItem() use IComboSelectionItem.equals() so it must compare the ID and |
// the flag since even if ID doesn't change the combo might get refreshed and the |
// selected row : |
// 1. get removed : in that case we want to add the "warning" item |
// 2. get added : in that case remove the "warning" |
// * ATTN item being null means id isn't in the result set, getSelectedValue() being |
// null means nothing is selected. For example if the current selection is empty and |
// now we want ID 34 but it isn't returned by the request, both will be null. |
if (item == null && this.addMissingItem()) { |
// si l'ID voulu n'est pas la, essayer d'aller le chercher directement dans la base |
// sans respecter le filtre |
final ComboSQLRequest comboSQLRequest = this.req.clone(); |
comboSQLRequest.setFilterEnabled(false); |
comboSQLRequest.setWhere(null); |
final ITransformer<SQLSelect, SQLSelect> transf = comboSQLRequest.getSelectTransf(); |
if (transf != null) |
comboSQLRequest.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(SQLSelect input) { |
final SQLSelect res = transf.transformChecked(input); |
res.setWhere(null); |
return res; |
} |
}); |
IComboSelectionItem newItem = comboSQLRequest.getComboItem(id); |
if (newItem != null) { |
newItem.setFlag(IComboSelectionItem.WARNING_FLAG); |
final boolean forceIncludeChanged = this.setSearchForceInclude(id); |
log("valid id : " + id + " forceIncludeChanged: " + forceIncludeChanged + " item: " + item); |
if (forceIncludeChanged && item == null) { |
this.fillCombo(); |
assert this.isUpdating() : "If not isUpdating(), getValue() will return the current UI value instead of the wantedID"; |
this.setWantedID(id); |
} else { |
// * setSelectedItem() use IComboSelectionItem.equals() so it must compare the ID |
// and the flag since even if ID doesn't change the combo might get refreshed and |
// the selected row : |
// 1. get removed : in that case we want to add the "warning" item |
// 2. get added : in that case remove the "warning" |
// * ATTN item being null means id isn't in the result set, getSelectedValue() being |
// null means nothing is selected. For example if the current selection is empty and |
// now we want ID 34 but it isn't returned by the request, both will be null. |
if (item == null && this.addMissingItem()) { |
// si l'ID voulu n'est pas là, essayer d'aller le chercher directement dans la |
// base sans respecter le filtre |
final ComboSQLRequest comboSQLRequest = this.req.clone(); |
comboSQLRequest.setFilterEnabled(false); |
comboSQLRequest.setWhere(null); |
final ITransformer<SQLSelect, SQLSelect> transf = comboSQLRequest.getSelectTransf(); |
if (transf != null) |
comboSQLRequest.setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(SQLSelect input) { |
final SQLSelect res = transf.transformChecked(input); |
res.setWhere(null); |
return res; |
} |
}); |
IComboSelectionItem newItem = comboSQLRequest.getComboItem(id); |
if (newItem != null) { |
newItem.setFlag(IComboSelectionItem.WARNING_FLAG); |
} else { |
// TODO y faire un cran plus haut pour savoir quelle table référence |
// cette erreur |
new IllegalStateException("ID " + id + " cannot be found in " + this.req).printStackTrace(); |
final SQLRow row = new SQLRow(this.req.getPrimaryTable(), id); |
final String error; |
if (!row.exists()) |
error = " inexistante"; |
else if (row.isArchived()) |
error = " archivée"; |
else |
error = " existe mais est non atteignable: " + row.findDistantArchived(2); |
newItem = new IComboSelectionItem(row, "ERREUR !!! " + row + error); |
newItem.setFlag(IComboSelectionItem.ERROR_FLAG); |
} |
this.addItem(newItem); |
this.setSelectedItem(newItem); |
} else { |
// TODO y faire un cran plus haut pour savoir quelle table référence |
// cette erreur |
new IllegalStateException("ID " + id + " cannot be found in " + this.req).printStackTrace(); |
final SQLRow row = new SQLRow(this.req.getPrimaryTable(), id); |
final String error; |
if (!row.exists()) |
error = " inexistante"; |
else if (row.isArchived()) |
error = " archivée"; |
else |
error = " existe mais est non atteignable: " + row.findDistantArchived(2); |
newItem = new IComboSelectionItem(row, "ERREUR !!! " + row + error); |
newItem.setFlag(IComboSelectionItem.ERROR_FLAG); |
this.setSelectedItem(item); |
} |
this.addItem(newItem); |
this.setSelectedItem(newItem); |
} else { |
this.setSelectedItem(item); |
} |
} |
} |
787,21 → 833,66 |
@Override |
public boolean isSearchable() { |
return !this.getRequest().getSearchFields().isEmpty(); |
return this.reqSearchable; |
} |
private final static Pattern QUERY_SPLIT_PATTERN = Pattern.compile("\\s+"); |
/** |
* Set the search query. The query will be used to match rows using |
* {@link ComboSQLRequest#setSearchFields(java.util.Collection)}. I.e. if there's no field set, |
* this method won't have any effect. |
* |
* @param s the search query. |
* @param r {@inheritDoc} |
* @return {@inheritDoc} |
*/ |
@Override |
public boolean setSearch(String s, Runnable r) { |
if (this.getRequest().setSearch(s)) { |
if (r != null) { |
synchronized (this) { |
this.runnables.add(r); |
// no need to trim() since trailing empty strings are not returned |
final List<String> split = StringUtils.isEmpty(s) ? Collections.<String> emptyList() : Arrays.asList(QUERY_SPLIT_PATTERN.split(s)); |
boolean res = false; |
synchronized (this) { |
if (!split.equals(this.searchQuery)) { |
this.searchQuery = split; |
if (this.isSearchable()) { |
res = true; |
} |
} |
return true; |
} else { |
SwingUtilities.invokeLater(r); |
log("setSearch() fillCombo: " + res + " query: " + this.searchQuery); |
} |
if (res) { |
this.fillCombo(r, true); |
} else if (r != null) { |
SwingThreadUtils.invoke(r); |
} |
return res; |
} |
private synchronized List<String> getSearchQuery() { |
assert this.searchQuery != null : "Null query means don't use the search which should only be governed by isSearchable()"; |
return this.isSearchable() ? this.searchQuery : null; |
} |
private boolean setSearchForceInclude(final int id) { |
if (!this.isSearchable()) { |
assert this.getSearchForceInclude() == null; |
return false; |
} |
final Where newVal = id != SQLRow.NONEXISTANT_ID ? new Where(getRequest().getPrimaryTable().getKey(), "=", id) : null; |
final boolean changed; |
synchronized (this) { |
changed = !CompareUtils.equals(this.searchForceInclude, newVal); |
if (changed) { |
this.searchForceInclude = newVal; |
} |
} |
// don't fillCombo() (as when searchQuery is changed) since we want to avoid it if the ID is |
// available |
return changed; |
} |
private synchronized Where getSearchForceInclude() { |
return this.searchForceInclude; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/IComboSelectionItem.java |
---|
20,6 → 20,8 |
import org.openconcerto.ui.component.combo.VarDesc; |
import org.openconcerto.utils.CompareUtils; |
import java.util.Comparator; |
/** |
* @author ILM Informatique |
*/ |
35,6 → 37,19 |
private final String fLabel; |
private int flag; |
public static final Comparator<? super IComboSelectionItem> CASE_SENSITIVE_LABEL_COMPARATOR = new Comparator<IComboSelectionItem>() { |
@Override |
public int compare(IComboSelectionItem o1, IComboSelectionItem o2) { |
return o1.getLabel().compareTo(o2.getLabel()); |
} |
}; |
public static final Comparator<? super IComboSelectionItem> CASE_INSENSITIVE_LABEL_COMPARATOR = new Comparator<IComboSelectionItem>() { |
@Override |
public int compare(IComboSelectionItem o1, IComboSelectionItem o2) { |
return o1.getLabel().compareToIgnoreCase(o2.getLabel()); |
} |
}; |
public IComboSelectionItem(final int id, final String label) { |
this(null, id, label); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLRequestComboBox.java |
---|
23,6 → 23,7 |
import org.openconcerto.sql.request.ComboSQLRequest.KeepMode; |
import org.openconcerto.sql.request.SQLForeignRowItemView; |
import org.openconcerto.sql.request.SQLRowItemView; |
import org.openconcerto.sql.view.list.ITableModel.SleepState; |
import org.openconcerto.sql.view.search.SearchSpec; |
import org.openconcerto.ui.FontUtils; |
import org.openconcerto.ui.component.ComboLockedMode; |
228,7 → 229,7 |
// CloturePayeMensuellePanel) |
SwingUtilities.invokeLater(new Runnable() { |
public void run() { |
SQLRequestComboBox.this.req.setOnScreen(true); |
updateListeners(); |
} |
}); |
} |
235,7 → 236,7 |
@Override |
public void ancestorRemoved(AncestorEvent event) { |
SQLRequestComboBox.this.req.setOnScreen(false); |
updateListeners(); |
} |
@Override |
288,25 → 289,14 |
this.uiLayout(); |
// Initialise UI : mode was set in the constructor, but the UI wasn't updated (since it |
// is |
// either not created or depending on the request). Do it before setRunning() since it |
// might |
// trigger setEnabled() and the one below would be unnecessary. |
// Initialise UI : mode attribute was set in the constructor, but the UI wasn't updated |
// since it wasn't created (and lacking the request). If updateEnabled() doesn't set the |
// mode, set it with the value set in the constructor. |
if (!updateEnabled()) |
this.setInteractionMode(this.getInteractionMode()); |
// *without* : resetValue() => doUpdateAll() since it was never filled |
// then this is made displayable => setRunning(true) => dirty = true since not on screen |
// finally made visible => setOnScreen(true) => second doUpdateAll() |
// *with* : setRunning(true) => update ignored since not on screen, dirty = true |
// resetValue() => doUpdateAll() since it was never filled, dirty = false |
// then this is made displayable => setRunning(true) => no change |
// finally made visible => setOnScreen(true) => not dirty => no update |
this.req.setRunning(true); |
} |
// return true if setEnabled() was called |
private final boolean updateEnabled() { |
boolean res = false; |
if (isDisabledState()) { |
344,7 → 334,14 |
protected void updateListeners() { |
if (hasModel()) { |
this.req.setRunning(this.isDisplayable()); |
final SleepState newState; |
if (!this.isDisplayable()) |
newState = SleepState.HIBERNATING; |
else if (!this.isShowing()) |
newState = SleepState.SLEEPING; |
else |
newState = SleepState.AWAKE; |
this.req.setSleepState(newState); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/itemview/VWRowItemView.java |
---|
155,7 → 155,7 |
} |
@Override |
public void removeValueListener(PropertyChangeListener l) { |
public final void removeValueListener(PropertyChangeListener l) { |
assert SwingUtilities.isEventDispatchThread(); |
this.supp.removePropertyChangeListener(VALUE_PROPNAME, l); |
if (!this.supp.hasListeners(VALUE_PROPNAME)) { |
181,7 → 181,7 |
} |
@Override |
public void removeEmptyListener(EmptyListener l) { |
public final void removeEmptyListener(EmptyListener l) { |
this.helper.removeEmptyListener(l); |
} |
198,7 → 198,7 |
} |
@Override |
public void removeValidListener(ValidListener l) { |
public final void removeValidListener(ValidListener l) { |
this.getWrapper().removeValidListener(new ChainValidListener(this, l)); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ElementComboBox.java |
---|
22,6 → 22,7 |
import org.openconcerto.sql.request.SQLRowItemView; |
import org.openconcerto.sql.view.EditFrame; |
import org.openconcerto.sql.view.EditPanel; |
import org.openconcerto.sql.view.EditPanel.EditMode; |
import org.openconcerto.sql.view.EditPanelListener; |
import org.openconcerto.sql.view.IListButton; |
import org.openconcerto.sql.view.IListFrame; |
289,7 → 290,7 |
} |
if (!displayed) { |
if (this.viewFrame == null) { |
this.viewFrame = new EditFrame(this.element, this.isModif ? EditPanel.MODIFICATION : EditPanel.READONLY); |
this.viewFrame = createEditFrame(this.isModif ? EditPanel.MODIFICATION : EditPanel.READONLY); |
// dispose since if we change canModif, the old frame will be orphaned |
this.viewFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); |
} |
318,7 → 319,7 |
private final EditFrame getAddFrame() { |
if (this.addFrame == null) { |
this.addFrame = new EditFrame(this.element, EditPanel.CREATION); |
this.addFrame = createEditFrame(EditPanel.CREATION); |
this.addFrame.addEditPanelListener(new EditPanelListener() { |
@Override |
public void cancelled() { |
341,6 → 342,17 |
return this.addFrame; |
} |
protected final EditFrame createEditFrame(final EditMode mode) { |
final SQLComponent res = this.createSQLComponent(mode); |
if (res.getElement() != this.getElement()) |
throw new IllegalStateException("Wrong element"); |
return new EditFrame(res, mode); |
} |
protected SQLComponent createSQLComponent(final EditMode mode) { |
return this.element.createDefaultComponent(); |
} |
/** |
* The sql component of the add frame. |
* |
/trunk/OpenConcerto/src/org/openconcerto/sql/Configuration.java |
---|
16,22 → 16,6 |
*/ |
package org.openconcerto.sql; |
import java.io.File; |
import java.io.IOException; |
import java.io.StringReader; |
import java.util.List; |
import java.util.concurrent.Executor; |
import java.util.concurrent.ExecutorService; |
import java.util.concurrent.Executors; |
import javax.xml.parsers.DocumentBuilder; |
import javax.xml.parsers.DocumentBuilderFactory; |
import javax.xml.parsers.ParserConfigurationException; |
import org.w3c.dom.Document; |
import org.xml.sax.InputSource; |
import org.xml.sax.SAXException; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.element.SQLElementDirectory; |
import org.openconcerto.sql.model.DBFileCache; |
48,7 → 32,26 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.request.SQLFieldTranslator; |
import org.openconcerto.utils.BaseDirs; |
import org.openconcerto.utils.FileUtils; |
import org.openconcerto.utils.StringUtils; |
import java.io.File; |
import java.io.IOException; |
import java.io.StringReader; |
import java.util.List; |
import java.util.concurrent.Executor; |
import java.util.concurrent.ExecutorService; |
import java.util.concurrent.Executors; |
import javax.xml.parsers.DocumentBuilder; |
import javax.xml.parsers.DocumentBuilderFactory; |
import javax.xml.parsers.ParserConfigurationException; |
import org.w3c.dom.Document; |
import org.xml.sax.InputSource; |
import org.xml.sax.SAXException; |
import net.jcip.annotations.GuardedBy; |
/** |
75,8 → 78,24 |
public static final void setInstance(Configuration instance) { |
Configuration.instance = instance; |
try { |
instance.migrateToNewDBConfDir(); |
} catch (IOException e) { |
throw new IllegalStateException("Couldn't migrate"); |
} |
} |
static public final void migrateToNewDir(final File oldDir, final File newDir) throws IOException { |
if (oldDir.exists() && !newDir.exists()) { |
if (!oldDir.isDirectory()) |
throw new IOException("Old file isn't a directory : " + oldDir); |
FileUtils.mkdir_p(newDir.getParentFile()); |
final String err = FileUtils.mv(oldDir, newDir); |
if (err != null) |
throw new IOException("Couldn't migrate from " + oldDir + " : " + err); |
} |
} |
@GuardedBy("this") |
private ExecutorService nonInteractiveSQLExecutor; |
112,16 → 131,27 |
*/ |
public final String getAppID() { |
final String appName = this.getAppName(); |
if (appName == null || appName.length() == 0) |
if (StringUtils.isEmpty(appName)) |
return null; |
return appName + getAppIDSuffix(); |
final String variant = this.getAppVariant(); |
if (StringUtils.isEmpty(variant, true)) |
return appName; |
return appName + '-' + variant; |
} |
protected String getAppIDSuffix() { |
return ""; |
public String getAppVariant() { |
return null; |
} |
public File getConfDir() { |
public abstract BaseDirs getBaseDirs(); |
public final File getConfDir() { |
return getBaseDirs().getPreferencesFolder(); |
} |
// for migration use |
@Deprecated |
protected File getOldConfDir() { |
return new File(getDefaultConfDir(), this.getAppID()); |
} |
134,30 → 164,29 |
return getConfDir(getRoot()); |
} |
/** |
* Move {@link #getConfDir()}/<code>name</code> to {@link #getConfDirForRoot()}/ |
* <code>name</code> if necessary. |
* |
* @param name the name of the file or directory to move. |
* @return the new file in <code>getConfDirForRoot()</code>. |
*/ |
public final File migrateToConfDirForRoot(final String name) { |
final File oldFile = new File(this.getConfDir(), name); |
final File newFile = new File(this.getConfDirForRoot(), name); |
if (oldFile.exists() && !newFile.exists()) { |
try { |
FileUtils.mkdir_p(newFile.getParentFile()); |
oldFile.renameTo(newFile); |
} catch (IOException e) { |
e.printStackTrace(); |
FileUtils.rmR(oldFile); |
} |
} |
return newFile; |
public final void migrateToNewDBConfDir() throws IOException { |
final File oldFile = getOldDBConfDir(); |
final File newFile = getDBConfDir(); |
migrateToNewDir(oldFile, newFile); |
} |
// for migration use |
private File getOldDBConfDir() { |
return new File(getOldConfDir(), "dataDepedent"); |
} |
// for migration use |
@Deprecated |
protected final File getOldConfDir(DBStructureItem<?> db) { |
return DBItemFileCache.getDescendant(getOldDBConfDir(), DBFileCache.getJDBCAncestorNames(db, true)); |
} |
private File getDBConfDir() { |
return new File(getConfDir(), "dataDependent"); |
} |
public final File getConfDir(DBStructureItem<?> db) { |
return DBItemFileCache.getDescendant(new File(getConfDir(), "dataDepedent"), DBFileCache.getJDBCAncestorNames(db, true)); |
return DBItemFileCache.getDescendant(getDBConfDir(), DBFileCache.getJDBCAncestorNames(db, true)); |
} |
/** |
188,11 → 217,13 |
/** |
* Get xml value from table FWK_LIST_PREFS for an user and a table. |
* |
* @throws ParserConfigurationException |
* @throws IOException |
* @throws SAXException |
* @param userId - Id of user |
* @param idTable - Id of table |
* |
* @throws IllegalStateException |
* @throws IllegalArgumentException |
*/ |
public Document getXMLConf(final long userId, final String idTable) throws ParserConfigurationException, SAXException, IOException { |
public Document getXMLConf(final Number userId, final String idTable) throws IllegalStateException, IllegalArgumentException { |
final SQLElement element = this.getDirectory().getElement("FWK_LIST_PREFS"); |
final SQLTable columnPrefsTable = element.getTable(); |
final SQLSelect select = new SQLSelect(); |
201,13 → 232,41 |
final List<SQLRow> rqResult = SQLRowListRSH.execute(select); |
if (rqResult != null && !rqResult.isEmpty()) { |
final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); |
final DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); |
return docBuilder.parse(new InputSource(new StringReader(rqResult.get(0).getString("VALUE")))); |
DocumentBuilder docBuilder; |
try { |
docBuilder = docFactory.newDocumentBuilder(); |
} catch (final ParserConfigurationException ex) { |
throw new IllegalStateException("Impossible to create new XML document", ex); |
} |
try { |
return docBuilder.parse(new InputSource(new StringReader(rqResult.get(0).getString("VALUE")))); |
} catch (final SAXException ex) { |
throw new IllegalArgumentException("Impossible to parse XML from database", ex); |
} catch (final IOException ex) { |
throw new IllegalStateException("Impossible to read content of database", ex); |
} |
} |
return null; |
} |
/** |
* Remove XML value from table FWK_LIST_PREFS for an user and a table. |
* |
* @param userId - Id of user |
* @param idTable - Id of table |
* |
* @throws IllegalStateException |
* @throws IllegalArgumentException |
*/ |
public void removeXMLConf(final Number userId, final String idTable) throws IllegalStateException, IllegalArgumentException { |
final SQLElement element = this.getDirectory().getElement("FWK_LIST_PREFS"); |
final SQLTable columnPrefsTable = element.getTable(); |
this.getRoot().getDBSystemRoot().getDataSource().execute("DELETE FROM " + columnPrefsTable.getSQLName().quote() + " WHERE \"ID_USER\" = " + userId + " AND \"ID_TABLE\" = '" + idTable + "'"); |
} |
/** |
* An executor that should be used for background SQL requests. It can be used to limit the |
* concurrent number of database connections (as establishing a connection is expensive and the |
* server might have restrictions). |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLRowView.java |
---|
16,7 → 16,6 |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.element.SQLComponent; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
37,7 → 36,6 |
import java.util.Collection; |
import java.util.Collections; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.LinkedHashSet; |
import java.util.LinkedList; |
import java.util.List; |
410,19 → 408,6 |
this.select(null); |
} |
/* |
* (non-Javadoc) |
* |
* @see org.openconcerto.devis.request.BaseSQLRequest#getAllFields() |
*/ |
public Collection<SQLField> getAllFields() { |
final Set<SQLField> res = new HashSet<SQLField>(); |
for (final SQLRowItemView view : this.getViewsFast()) { |
res.addAll(view.getFields()); |
} |
return res; |
} |
private void setSelectedID(int selectedID) { |
this.selectedID = selectedID; |
if (!existsInDB()) |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ComboSQLRequest.java |
---|
17,17 → 17,17 |
* @author ILM Informatique |
*/ |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.TransfFieldExpander; |
import org.openconcerto.sql.FieldExpander; |
import org.openconcerto.sql.element.SQLElementDirectory; |
import org.openconcerto.sql.model.FieldPath; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLRowValuesListFetcher; |
import org.openconcerto.sql.model.SQLSearchMode; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.model.graph.Path; |
import org.openconcerto.sql.sqlobject.ElementComboBoxUtils; |
import org.openconcerto.sql.sqlobject.IComboSelectionItem; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.CompareUtils; |
43,6 → 43,8 |
import java.util.Collections; |
import java.util.Comparator; |
import java.util.List; |
import java.util.ListIterator; |
import java.util.Locale; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.Immutable; |
50,7 → 52,7 |
// final: use setSelectTransf() |
@ThreadSafe |
public final class ComboSQLRequest extends FilteredFillSQLRequest { |
public final class ComboSQLRequest extends FilteredFillSQLRequest implements Cloneable { |
static private final SQLCache<CacheKey, List<IComboSelectionItem>> cache = new SQLCache<CacheKey, List<IComboSelectionItem>>(60, -1, "items of " + ComboSQLRequest.class); |
61,6 → 63,10 |
private final SQLRowValues graph; |
private final SQLRowValuesListFetcher fetcher; |
private final Where where; |
private final ITransformer<SQLSelect, SQLSelect> selTransformer; |
// compute request once and for all to speed up equals (OK since the fetcher and its |
// parameter are immutable) |
private final String select; |
private final String fieldSeparator; |
private final String undefLabel; |
private final KeepMode keepRows; |
68,8 → 74,9 |
private final IClosure<IComboSelectionItem> customizeItem; |
private final Comparator<? super IComboSelectionItem> itemsOrder; |
public CacheKey(SQLRowValues graph, SQLRowValuesListFetcher f, Where w, String fieldSeparator, String undefLabel, IClosure<IComboSelectionItem> c, KeepMode keepRows, |
Comparator<? super IComboSelectionItem> itemsOrder) { |
// ATTN selTransformer (as the fetcher and the where) should be immutable |
public CacheKey(SQLRowValues graph, SQLRowValuesListFetcher f, Where w, ITransformer<SQLSelect, SQLSelect> selTransformer, String fieldSeparator, String undefLabel, |
IClosure<IComboSelectionItem> c, KeepMode keepRows, Comparator<? super IComboSelectionItem> itemsOrder) { |
super(); |
if (!graph.isFrozen()) |
throw new IllegalArgumentException("Not frozen : " + graph); |
80,6 → 87,8 |
throw new IllegalArgumentException("Not frozen : " + f); |
this.fetcher = f; |
this.where = w; |
this.selTransformer = selTransformer; |
this.select = this.fetcher.getReq(this.where, this.selTransformer).asString(); |
this.fieldSeparator = fieldSeparator; |
this.undefLabel = undefLabel; |
108,12 → 117,12 |
public boolean equals(Object obj) { |
if (this == obj) |
return true; |
if (getClass() != obj.getClass()) |
if (obj == null || getClass() != obj.getClass()) |
return false; |
final CacheKey other = (CacheKey) obj; |
return this.keepRows == other.keepRows && this.fieldSeparator.equals(other.fieldSeparator) && CompareUtils.equals(this.undefLabel, other.undefLabel) |
&& CompareUtils.equals(this.where, other.where) && this.graph.getGraphFirstDifference(other.graph, true) == null && CompareUtils.equals(this.fetcher, other.fetcher) |
&& CompareUtils.equals(this.customizeItem, other.customizeItem) && CompareUtils.equals(this.itemsOrder, other.itemsOrder); |
&& this.graph.getGraphFirstDifference(other.graph, true) == null && this.select.equals(other.select) && CompareUtils.equals(this.customizeItem, other.customizeItem) |
&& CompareUtils.equals(this.itemsOrder, other.itemsOrder); |
} |
}; |
164,10 → 173,21 |
setDefaultItemsOrder(null); |
} |
private static final SQLElementDirectory getDirectory(final SQLElementDirectory dir) { |
if (dir != null) |
return dir; |
final Configuration conf = Configuration.getInstance(); |
return conf == null ? null : conf.getDirectory(); |
} |
private static final FieldExpander getExpander(SQLElementDirectory dir) { |
dir = getDirectory(dir); |
return dir != null ? ComboSQLRequestUtils.getShowAs(dir) : FieldExpander.getEmpty(); |
} |
// immutable |
@GuardedBy("this") |
private List<SQLField> comboFields; |
private final TransfFieldExpander exp; |
private final SQLElementDirectory dir; |
@GuardedBy("this") |
private String fieldSeparator = getDefaultFieldSeparator(); |
179,8 → 199,6 |
private IClosure<IComboSelectionItem> customizeItem; |
@GuardedBy("this") |
private List<Path> order; |
@GuardedBy("this") |
private Comparator<? super IComboSelectionItem> itemsOrder; |
public ComboSQLRequest(SQLTable table, List<String> l) { |
188,23 → 206,27 |
} |
public ComboSQLRequest(SQLTable table, List<String> l, Where where) { |
super(table, where); |
this(table, l, where, null); |
} |
public ComboSQLRequest(SQLTable table, List<String> l, Where where, final SQLElementDirectory dir) { |
this(computeGraph(table, l, getExpander(dir)), where, dir); |
} |
public ComboSQLRequest(SQLRowValues graph, Where where, final SQLElementDirectory dir) { |
super(graph, where); |
this.dir = dir; |
this.undefLabel = null; |
// don't use memory |
this.keepRows = KeepMode.NONE; |
this.customizeItem = null; |
this.order = null; |
this.itemsOrder = getDefaultItemsOrder(); |
this.exp = ElementComboBoxUtils.getShowAs(Configuration.getInstance()); |
this.setFields(l); |
} |
protected ComboSQLRequest(ComboSQLRequest c, final boolean freeze) { |
super(c, freeze); |
this.exp = new TransfFieldExpander(c.exp); |
this.dir = c.dir; |
synchronized (c) { |
this.comboFields = c.comboFields; |
this.order = c.order == null ? null : new ArrayList<Path>(c.order); |
this.itemsOrder = c.itemsOrder; |
this.fieldSeparator = c.fieldSeparator; |
214,6 → 236,10 |
} |
} |
private final SQLElementDirectory getDirectory() { |
return getDirectory(this.dir); |
} |
@Override |
public ComboSQLRequest toUnmodifiable() { |
return this.toUnmodifiableP(this.getClass()); |
231,27 → 257,6 |
return new ComboSQLRequest(this, forFreeze); |
} |
public final void setFields(Collection<String> fields) { |
final List<SQLField> l = new ArrayList<SQLField>(); |
for (final String fName : fields) { |
l.add(this.getPrimaryTable().getField(fName)); |
} |
setSQLFieldsUnsafe(l); |
} |
public final void setSQLFields(Collection<SQLField> fields) { |
for (final SQLField f : fields) |
if (f.getTable() != getPrimaryTable()) |
throw new IllegalArgumentException("Not in " + getPrimaryTable() + " : " + f); |
setSQLFieldsUnsafe(new ArrayList<SQLField>(fields)); |
} |
private synchronized void setSQLFieldsUnsafe(List<SQLField> fields) { |
checkFrozen(); |
this.comboFields = Collections.unmodifiableList(fields); |
this.clearGraph(); |
} |
/** |
* Set the label of the undefined row. If <code>null</code> (the default) then the undefined |
* will not be fetched, otherwise it will and its label will be <code>undefLabel</code>. |
281,7 → 286,7 |
*/ |
public final IComboSelectionItem getComboItem(int id) { |
// historically this method didn't use the cache |
final List<IComboSelectionItem> res = getComboItems(id, false, false); |
final List<IComboSelectionItem> res = getComboItems(id, null, null, null, false, false); |
return getSole(res, id); |
} |
290,17 → 295,20 |
} |
public final List<IComboSelectionItem> getComboItems(final boolean readCache) { |
return this.getComboItems(null, readCache, true); |
return this.getComboItems(readCache, null, null, null); |
} |
private final List<IComboSelectionItem> getComboItems(final Number id, final boolean readCache, final boolean writeCache) { |
if (this.getFields().isEmpty()) |
throw new IllegalStateException("Empty fields"); |
public final List<IComboSelectionItem> getComboItems(final boolean readCache, final List<String> searchQuery, final Locale locale, final Where searchForceInclude) { |
return this.getComboItems(null, searchQuery, locale, searchForceInclude, readCache, true); |
} |
private final List<IComboSelectionItem> getComboItems(final Number id, final List<String> searchQuery, final Locale locale, final Where searchForceInclude, final boolean readCache, |
final boolean writeCache) { |
final Where w = id == null ? null : new Where(this.getPrimaryTable().getKey(), "=", id); |
// this encapsulates a snapshot of our state, so this method doesn't access any of our |
// fields and doesn't need to be synchronized |
final CacheKey cacheKey = getCacheKey(w); |
final CacheKey cacheKey = getCacheKey(w, searchQuery, locale, searchForceInclude); |
final SQLRowValuesListFetcher comboSelect = cacheKey.fetcher; |
final CacheResult<List<IComboSelectionItem>> l = cache.check(cacheKey, readCache, writeCache, comboSelect.getGraph().getGraph().getTables()); |
if (l.getState() == CacheResult.State.INTERRUPTED) |
311,10 → 319,10 |
try { |
// group fields by ancestor, need not be part of CacheKey assuming parent-child |
// relations don't change |
final List<Tuple2<Path, List<FieldPath>>> ancestors = ElementComboBoxUtils.expandGroupBy(cacheKey.graph, Configuration.getInstance().getDirectory()); |
final List<Tuple2<Path, List<FieldPath>>> ancestors = ComboSQLRequestUtils.expandGroupBy(cacheKey.graph, getDirectory()); |
final List<IComboSelectionItem> result = new ArrayList<IComboSelectionItem>(); |
// SQLRowValuesListFetcher doesn't cache |
for (final SQLRowValues vals : comboSelect.fetch(w)) { |
for (final SQLRowValues vals : comboSelect.fetch(w, cacheKey.selTransformer, null)) { |
if (Thread.currentThread().isInterrupted()) |
throw new RTInterruptedException("interrupted in fill"); |
// each item should be created with the same state and since it will be put in |
336,11 → 344,12 |
} |
protected final CacheKey getCacheKey() { |
return getCacheKey(null); |
return getCacheKey(null, null, null, null); |
} |
private final synchronized CacheKey getCacheKey(final Where w) { |
return new CacheKey(this.getGraph(), this.getFetcher(), w, this.fieldSeparator, this.undefLabel, this.customizeItem, this.keepRows, this.itemsOrder); |
private final synchronized CacheKey getCacheKey(final Where w, final List<String> searchQuery, final Locale l, final Where searchForceInclude) { |
return new CacheKey(this.getGraph(), this.getFetcher(), w, this.createSearchTransformer(searchQuery, l, searchForceInclude), this.fieldSeparator, this.undefLabel, this.customizeItem, |
this.keepRows, this.itemsOrder); |
} |
@Override |
350,12 → 359,26 |
} |
@Override |
protected synchronized final List<Path> getOrder() { |
if (this.order != null) |
return this.order; |
protected Collection<SearchField> getDefaultSearchFields() { |
final List<SearchField> res = new ArrayList<SearchField>(); |
final List<Tuple2<Path, List<FieldPath>>> expandGroupBy = ComboSQLRequestUtils.expandGroupBy(getGraph(), getDirectory()); |
int rank = 10; |
final ListIterator<Tuple2<Path, List<FieldPath>>> iter = expandGroupBy.listIterator(expandGroupBy.size()); |
assert !iter.hasNext(); |
while (iter.hasPrevious()) { |
final Tuple2<Path, List<FieldPath>> element = iter.previous(); |
for (final FieldPath fp : element.get1()) { |
res.add(new SearchField(fp, SQLSearchMode.CONTAINS, rank)); |
} |
rank *= 5; |
} |
return res; |
} |
@Override |
protected List<Path> getDefaultOrder() { |
// order the combo by ancestors |
final List<Tuple2<Path, List<FieldPath>>> expandGroupBy = ElementComboBoxUtils.expandGroupBy(getGraph(), Configuration.getInstance().getDirectory()); |
final List<Tuple2<Path, List<FieldPath>>> expandGroupBy = ComboSQLRequestUtils.expandGroupBy(getGraph(), getDirectory()); |
final List<Path> res = new ArrayList<Path>(expandGroupBy.size()); |
for (final Tuple2<Path, List<FieldPath>> ancestor : expandGroupBy) |
res.add(0, ancestor.get0()); |
362,17 → 385,6 |
return res; |
} |
/** |
* Change the ordering of this combo. By default this is ordered by ancestors. |
* |
* @param l the list of tables, <code>null</code> to restore the default. |
*/ |
public synchronized final void setOrder(List<Path> l) { |
checkFrozen(); |
this.order = Collections.unmodifiableList(new ArrayList<Path>(l)); |
this.clearGraph(); |
} |
public final void setNaturalItemsOrder(final boolean b) { |
this.setItemsOrder(b ? CompareUtils.<IComboSelectionItem> naturalOrder() : null); |
} |
422,11 → 434,6 |
return res; |
} |
@Override |
protected final TransfFieldExpander getShowAs() { |
return this.exp; |
} |
/** |
* Renvoie la valeur du champ sous forme de String. De plus est sensé faire quelques |
* conversions, eg traduire les booléens en "oui" "non". |
446,11 → 453,6 |
return result; |
} |
@Override |
public synchronized final List<SQLField> getFields() { |
return this.comboFields; |
} |
/** |
* Set the string that is used to join the fields of a row. |
* |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/UpdateBuilder.java |
---|
15,6 → 15,7 |
import static java.util.Collections.unmodifiableList; |
import static java.util.Collections.unmodifiableMap; |
import org.openconcerto.sql.model.SQLBase; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLName; |
62,6 → 63,10 |
return this.t; |
} |
public final SQLSyntax getSyntax() { |
return SQLSyntax.get(this.getTable()); |
} |
private final void checkField(final String field) { |
checkField(field, getTable()); |
} |
242,7 → 247,7 |
computedWhere = w.and(computedWhere); |
} |
final String w = computedWhere == null ? "" : "\nWHERE " + computedWhere.getClause(); |
return "UPDATE " + this.getTable().getServer().getSQLSystem().getSyntax().getUpdate(this.getTable(), unmodifiableList(computedTables), unmodifiableMap(this.fields)) + w; |
return "UPDATE " + this.getSyntax().getUpdate(this.getTable(), unmodifiableList(computedTables), unmodifiableMap(this.fields)) + w; |
} |
@Override |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/Inserter.java |
---|
13,10 → 13,13 |
package org.openconcerto.sql.request; |
import org.openconcerto.sql.model.ColumnListHandlerGeneric; |
import org.openconcerto.sql.model.ConnectionHandlerNoSetup; |
import org.openconcerto.sql.model.DBRoot; |
import org.openconcerto.sql.model.DBSystemRoot; |
import org.openconcerto.sql.model.ListListHandlerGeneric; |
import org.openconcerto.sql.model.SQLDataSource; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLName; |
import org.openconcerto.sql.model.SQLSystem; |
import org.openconcerto.sql.model.SQLTable; |
26,7 → 29,9 |
import java.sql.SQLException; |
import java.sql.Statement; |
import java.util.ArrayList; |
import java.util.List; |
import java.util.Set; |
/** |
* Allow to insert some rows into a table and get some feedback. |
40,6 → 45,12 |
} |
public static final class Insertion<T> { |
// syntactic sugar to allow new Insertion<?>() |
static public final <I> Insertion<I> create(List<I> res, int count) { |
return new Insertion<I>(res, count); |
} |
private final List<T> list; |
private final int count; |
73,12 → 84,24 |
private static final String[] EMPTY_ARRAY = new String[0]; |
private static List<Class<?>> getPKTypes(SQLTable t) { |
final Set<SQLField> pk = t.getPrimaryKeys(); |
final List<Class<?>> res = new ArrayList<Class<?>>(pk.size()); |
for (final SQLField f : pk) { |
res.add(f.getType().getJavaType()); |
} |
return res; |
} |
private final List<String> pk; |
private final List<Class<?>> pkTypes; |
private final DBSystemRoot sysRoot; |
private final SQLName tableName; |
public Inserter(final SQLTable t) { |
this(t.getDBSystemRoot(), t.getSQLName(), t.getPKsNames()); |
// pass types since we can't always rely on ResultSet.getObject() for generated keys (e.g. |
// MySQL always return BigInt no matter the actual type of the keys) |
this(t.getDBSystemRoot(), t.getSQLName(), t.getPKsNames(), getPKTypes(t)); |
} |
public Inserter(final SQLCreateTable t) { |
90,6 → 113,10 |
} |
public Inserter(final DBSystemRoot sysRoot, final SQLName tableName, final List<String> pk) { |
this(sysRoot, tableName, pk, null); |
} |
public Inserter(final DBSystemRoot sysRoot, final SQLName tableName, final List<String> pk, final List<Class<?>> pkTypes) { |
super(); |
if (sysRoot == null || tableName == null) |
throw new NullPointerException(); |
96,6 → 123,9 |
this.sysRoot = sysRoot; |
this.tableName = tableName; |
this.pk = pk; |
this.pkTypes = pkTypes == null ? null : new ArrayList<Class<?>>(pkTypes); |
if (this.pkTypes != null && this.pkTypes.size() != this.pk.size()) |
throw new IllegalArgumentException("Size mismatch"); |
} |
protected final SQLSystem getSystem() { |
119,8 → 149,8 |
* @throws SQLException if an error occurs while inserting. |
*/ |
@SuppressWarnings("unchecked") |
public final Insertion<Object[]> insertReturnAllFields(final String sql) throws SQLException { |
return (Insertion<Object[]>) insert(sql, ReturnMode.ALL_FIELDS, true); |
public final Insertion<List<?>> insertReturnAllFields(final String sql) throws SQLException { |
return (Insertion<List<?>>) insert(sql, ReturnMode.ALL_FIELDS, true); |
} |
/** |
186,14 → 216,20 |
if (dontGetGK) { |
list = null; |
} else { |
list = (List<?>) (mode == ReturnMode.FIRST_FIELD ? SQLDataSource.COLUMN_LIST_HANDLER : SQLDataSource.ARRAY_LIST_HANDLER).handle(stmt.getGeneratedKeys()); |
if (Inserter.this.pkTypes == null) { |
list = (List<?>) (mode == ReturnMode.FIRST_FIELD ? SQLDataSource.COLUMN_LIST_HANDLER : SQLDataSource.LIST_LIST_HANDLER).handle(stmt.getGeneratedKeys()); |
} else { |
if (mode == ReturnMode.FIRST_FIELD) { |
list = ColumnListHandlerGeneric.create(1, Inserter.this.pkTypes.get(0)).handle(stmt.getGeneratedKeys()); |
} else { |
list = ListListHandlerGeneric.create(Object.class, Inserter.this.pkTypes).handle(stmt.getGeneratedKeys()); |
} |
} |
assert list.size() <= count; |
if (requireAllRows && list.size() != count) |
throw new IllegalStateException("Missing keys"); |
} |
@SuppressWarnings("unchecked") |
final Insertion<?> res = new Insertion<Object>((List<Object>) list, count); |
return res; |
return Insertion.create(list, count); |
} finally { |
stmt.close(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/FilteredFillSQLRequest.java |
---|
89,8 → 89,8 |
}; |
} |
public FilteredFillSQLRequest(final SQLTable primaryTable, Where w) { |
super(primaryTable, w); |
public FilteredFillSQLRequest(final SQLRowValues graph, Where w) { |
super(graph, w); |
this.filter = getDefaultFilter(); |
this.filterInfo = Tuple2.create(null, null); |
this.setFilterEnabled(true); |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/BaseSQLRequest.java |
---|
13,14 → 13,6 |
package org.openconcerto.sql.request; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLFieldsSet; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import java.util.Collection; |
import java.util.Set; |
import net.jcip.annotations.ThreadSafe; |
@ThreadSafe |
29,27 → 21,4 |
public BaseSQLRequest() { |
super(); |
} |
public final Set<SQLTable> getTables() { |
return new SQLFieldsSet(this.getAllFields()).getTables(); |
} |
/** |
* Tous les champs qui intéressent cette requête. Souvent les champs après expansion. |
* |
* @return les champs qui intéressent cette requête. |
*/ |
protected abstract Collection<SQLField> getAllFields(); |
public final void addTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.addTableModifiedListener(l); |
} |
} |
public final void removeTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.removeTableModifiedListener(l); |
} |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ListSQLRequest.java |
---|
21,8 → 21,6 |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.Where; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.List; |
import net.jcip.annotations.ThreadSafe; |
30,60 → 28,41 |
@ThreadSafe |
public class ListSQLRequest extends FilteredFillSQLRequest { |
// les champs à afficher (avant expansion) |
// immutable |
private final List<SQLField> listFields; |
private static final FieldExpander getExpander(final FieldExpander showAs) { |
final FieldExpander res; |
if (showAs != null) { |
res = showAs; |
} else { |
final Configuration conf = Configuration.getInstance(); |
if (conf == null) { |
res = FieldExpander.getEmpty(); |
} else { |
res = conf.getShowAs(); |
} |
} |
return res; |
} |
private final FieldExpander showAs; |
public ListSQLRequest(SQLTable table, List fieldss) { |
public ListSQLRequest(SQLTable table, List<String> fieldss) { |
this(table, fieldss, null); |
} |
// fieldss : list de String (préferré) ou de SQLField |
public ListSQLRequest(SQLTable table, List fieldss, Where where) { |
public ListSQLRequest(SQLTable table, List<String> fieldss, Where where) { |
this(table, fieldss, where, null); |
} |
public ListSQLRequest(SQLTable table, List fieldss, Where where, final FieldExpander showAs) { |
super(table, where); |
public ListSQLRequest(SQLTable table, List<String> fieldss, Where where, final FieldExpander showAs) { |
this(computeGraph(table, fieldss, getExpander(showAs)), where); |
} |
public ListSQLRequest(final SQLRowValues graph, final Where where) { |
super(graph, where); |
if (!this.getPrimaryTable().isOrdered()) |
throw new IllegalArgumentException(table + " is not ordered."); |
final List<SQLField> tmpList = new ArrayList<SQLField>(); |
for (final Object field : fieldss) { |
final SQLField f; |
if (field instanceof String) |
f = this.getPrimaryTable().getField((String) field); |
else if (field instanceof SQLField) { |
final SQLField fToCheck = (SQLField) field; |
if (fToCheck.getTable().equals(this.getPrimaryTable())) |
f = fToCheck; |
else |
throw new IllegalArgumentException("field " + fToCheck + " not part of the primary table : " + this.getPrimaryTable()); |
} else |
throw new IllegalArgumentException("must be a fieldname or a SQLField but got : " + field); |
tmpList.add(f); |
} |
this.listFields = Collections.unmodifiableList(tmpList); |
if (showAs != null) { |
this.showAs = showAs; |
} else { |
final Configuration conf = Configuration.getInstance(); |
if (conf == null) { |
this.showAs = FieldExpander.getEmpty(); |
} else { |
this.showAs = conf.getShowAs(); |
} |
} |
throw new IllegalArgumentException(this.getPrimaryTable() + " is not ordered."); |
} |
protected ListSQLRequest(ListSQLRequest req, final boolean freeze) { |
super(req, freeze); |
this.listFields = req.listFields; |
this.showAs = req.showAs; |
} |
// wasFrozen() : our showAs might change but our fetcher won't, MAYBE remove final modifier and |
94,12 → 73,9 |
return this.toUnmodifiableP(ListSQLRequest.class); |
} |
@Override |
public ListSQLRequest clone() { |
synchronized (this) { |
return this.clone(false); |
} |
} |
// can't implement Cloneable since the contract is to return an object of the same class. But |
// this would either prevent the use of anonymous classes if we call clone(false), or require a |
// call to super.clone() and less final fields. |
@Override |
protected ListSQLRequest clone(boolean forFreeze) { |
106,23 → 82,9 |
return new ListSQLRequest(this, forFreeze); |
} |
// MAYBE use changeGraphToFetch() |
@Override |
protected FieldExpander getShowAs() { |
return this.showAs; |
} |
/* |
* (non-Javadoc) |
* |
* @see org.openconcerto.devis.request.BaseSQLRequest#getFields() |
*/ |
@Override |
public final List<SQLField> getFields() { |
return this.listFields; |
} |
@Override |
protected void customizeToFetch(SQLRowValues graphToFetch) { |
protected final void customizeToFetch(SQLRowValues graphToFetch) { |
super.customizeToFetch(graphToFetch); |
addField(graphToFetch, getPrimaryTable().getCreationDateField()); |
addField(graphToFetch, getPrimaryTable().getCreationUserField()); |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/ComboSQLRequestUtils.java |
---|
Nouveau fichier |
0,0 → 1,122 |
/* |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
* |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved. |
* |
* The contents of this file are subject to the terms of the GNU General Public License Version 3 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific |
* language governing permissions and limitations under the License. |
* |
* When distributing the software, include this License Header Notice in each file. |
*/ |
package org.openconcerto.sql.request; |
import org.openconcerto.sql.TransfFieldExpander; |
import org.openconcerto.sql.element.SQLElement; |
import org.openconcerto.sql.element.SQLElementDirectory; |
import org.openconcerto.sql.model.FieldPath; |
import org.openconcerto.sql.model.IFieldPath; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.graph.Link.Direction; |
import org.openconcerto.sql.model.graph.Path; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.ITransformer; |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.List; |
final class ComboSQLRequestUtils { |
// return the foreign row in field and its fields |
private static Tuple2<SQLRowValues, List<FieldPath>> expandOnce(final SQLRowValues vals, final IFieldPath field) { |
assert vals.getFields().contains(field.getFieldName()); |
final Object foreignObj = vals.getObject(field.getFieldName()); |
if (!(foreignObj instanceof SQLRowValues)) |
return Tuple2.create(null, Collections.<FieldPath> emptyList()); |
final SQLRowValues foreign = (SQLRowValues) foreignObj; |
// foreign since we used getObject() |
final Path newPath = field.getPath().add(field.getField(), Direction.FOREIGN); |
final List<FieldPath> res = new ArrayList<FieldPath>(); |
for (final String f : foreign.getFields()) |
res.add(new FieldPath(newPath, f)); |
return Tuple2.create(foreign, res); |
} |
// recursively walk vals to collect all foreign fields |
public static final List<FieldPath> expand(final SQLRowValues vals, final IFieldPath field) { |
assert vals.getTable() == field.getTable(); |
final List<FieldPath> fields = new ArrayList<FieldPath>(); |
if (!field.getTable().getForeignKeys().contains(field.getField())) { |
// si ce n'est pas une clef alors il n'y a pas à l'expandre |
fields.add(field.getFieldPath()); |
} else { |
final Tuple2<SQLRowValues, List<FieldPath>> tmp = expandOnce(vals, field); |
for (final FieldPath f : tmp.get1()) { |
fields.addAll(expand(tmp.get0(), f)); |
} |
} |
return fields; |
} |
/** |
* Group fields of the passed row by the parent foreign key. For each item of the result, the |
* path to the ancestor is also included, e.g. [ LOCAL, LOCAL.ID_BATIMENT, |
* LOCAL.ID_BATIMENT.ID_SITE, LOCAL.ID_BATIMENT.ID_SITE.ID_ETABLISSEMENT ]. |
* |
* @param vals the row to go through. |
* @param dir how to find the parents. |
* @return the complete expansion, e.g. [ [LOCAL.DESIGNATION], [BAT.DES], [SITE.DES, |
* ADRESSE.CP], [ETABLISSEMENT.DES] ]. |
*/ |
public static final List<Tuple2<Path, List<FieldPath>>> expandGroupBy(final SQLRowValues vals, final SQLElementDirectory dir) { |
return expandGroupBy(new Path(vals.getTable()), vals, dir); |
} |
private static final List<Tuple2<Path, List<FieldPath>>> expandGroupBy(final Path fieldsPath, final SQLRowValues vals, final SQLElementDirectory dir) { |
assert fieldsPath.getLast() == vals.getTable(); |
if (vals.size() == 0) |
return Collections.emptyList(); |
final SQLElement element = dir.getElement(fieldsPath.getLast()); |
// treat missing element as the root |
final SQLField parentFF = element == null ? null : element.getParentForeignField(); |
final List<Tuple2<Path, List<FieldPath>>> res = new ArrayList<Tuple2<Path, List<FieldPath>>>(); |
final List<FieldPath> currentL = new ArrayList<FieldPath>(); |
res.add(Tuple2.create(fieldsPath, currentL)); |
SQLRowValues parent = null; |
for (final String f : vals.getFields()) { |
if (parentFF != null && f.equals(parentFF.getName())) { |
final Object val = vals.getObject(f); |
parent = val instanceof SQLRowValues ? (SQLRowValues) val : null; |
} else { |
currentL.addAll(expand(vals, new FieldPath(fieldsPath, f))); |
} |
} |
if (parent != null) |
res.addAll(expandGroupBy(fieldsPath.add(parentFF, Direction.FOREIGN), parent, dir)); |
return res; |
} |
public static final TransfFieldExpander getShowAs(final SQLElementDirectory dir) { |
final TransfFieldExpander exp = new TransfFieldExpander(new ITransformer<SQLField, List<SQLField>>() { |
@Override |
public List<SQLField> transformChecked(SQLField fk) { |
final SQLTable foreignTable = fk.getDBSystemRoot().getGraph().getForeignTable(fk); |
return dir.getElement(foreignTable).getComboRequest().getFields(); |
} |
}); |
return exp; |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/BaseFillSQLRequest.java |
---|
14,7 → 14,9 |
package org.openconcerto.sql.request; |
import org.openconcerto.sql.FieldExpander; |
import org.openconcerto.sql.TM; |
import org.openconcerto.sql.model.FieldRef; |
import org.openconcerto.sql.model.IFieldPath; |
import org.openconcerto.sql.model.SQLField; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLRowValues.CreateMode; |
21,34 → 23,43 |
import org.openconcerto.sql.model.SQLRowValuesListFetcher; |
import org.openconcerto.sql.model.SQLSearchMode; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLSyntax; |
import org.openconcerto.sql.model.SQLSyntax.CaseBuilder; |
import org.openconcerto.sql.model.SQLSyntax.DateProp; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.model.SQLTable.VirtualFields; |
import org.openconcerto.sql.model.SQLTableModifiedListener; |
import org.openconcerto.sql.model.SQLType; |
import org.openconcerto.sql.model.Where; |
import org.openconcerto.sql.model.graph.Path; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.IClosure; |
import org.openconcerto.utils.cc.ITransformer; |
import java.beans.PropertyChangeListener; |
import java.beans.PropertyChangeSupport; |
import java.sql.Date; |
import java.sql.Time; |
import java.sql.Timestamp; |
import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.Collection; |
import java.util.Collections; |
import java.util.HashMap; |
import java.util.HashSet; |
import java.util.Iterator; |
import java.util.List; |
import java.util.Locale; |
import java.util.Map; |
import java.util.Map.Entry; |
import java.util.Set; |
import java.util.regex.Pattern; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.ThreadSafe; |
@ThreadSafe |
public abstract class BaseFillSQLRequest extends BaseSQLRequest implements Cloneable { |
public abstract class BaseFillSQLRequest extends BaseSQLRequest { |
private final static Pattern QUERY_SPLIT_PATTERN = Pattern.compile("\\s+"); |
private static boolean DEFAULT_SELECT_LOCK = true; |
/** |
75,32 → 86,39 |
fetcher.setReferentsOrdered(true, true); |
} |
static public final void addToFetch(final SQLRowValues input, final Path p, final Collection<String> fields) { |
static public final boolean addToFetch(final SQLRowValues input, final Path p, final Collection<String> fields) { |
assert p == null || p.isSingleLink() : "Graph size not sufficient to know if graph was modified"; |
final int graphSize = input.getGraphSize(); |
// don't back track : e.g. if path is SITE -> CLIENT <- SITE we want the siblings of SITE, |
// if we want fields of the primary SITE we pass the path SITE |
final SQLRowValues r = p == null ? input : input.followPathToOne(p, CreateMode.CREATE_ONE, false); |
boolean modified = input.getGraphSize() > graphSize; |
for (final String f : fields) { |
// don't overwrite foreign rows |
if (!r.getFields().contains(f)) |
// don't overwrite foreign rows and update modified |
if (!r.getFields().contains(f)) { |
r.put(f, null); |
modified = true; |
} |
} |
return modified; |
} |
private final SQLTable primaryTable; |
@GuardedBy("this") |
private List<Path> order; |
@GuardedBy("this") |
private Where where; |
@GuardedBy("this") |
private Map<SQLField, SQLSearchMode> searchFields; |
private Map<IFieldPath, SearchField> searchFields; |
@GuardedBy("this") |
private List<String> searchQuery; |
private int searchLimit; |
@GuardedBy("this") |
private ITransformer<SQLSelect, SQLSelect> selTransf; |
@GuardedBy("this") |
private boolean lockSelect; |
private final SQLRowValues graph; |
@GuardedBy("this") |
private SQLRowValues graph; |
@GuardedBy("this") |
private SQLRowValues graphToFetch; |
@GuardedBy("this") |
113,17 → 131,18 |
private final PropertyChangeSupport supp = new PropertyChangeSupport(this); |
public BaseFillSQLRequest(final SQLTable primaryTable, final Where w) { |
public BaseFillSQLRequest(final SQLRowValues graph, final Where w) { |
super(); |
if (primaryTable == null) |
if (graph == null) |
throw new NullPointerException(); |
this.primaryTable = primaryTable; |
this.primaryTable = graph.getTable(); |
this.setOrder(null); |
this.where = w; |
this.searchFields = Collections.emptyMap(); |
this.searchQuery = Collections.emptyList(); |
this.searchLimit = 35; |
this.selTransf = null; |
this.lockSelect = getDefaultLockSelect(); |
this.graph = null; |
this.graph = graph.toImmutable(); |
this.graphToFetch = null; |
} |
131,9 → 150,10 |
super(); |
this.primaryTable = req.getPrimaryTable(); |
synchronized (req) { |
this.order = req.order; |
this.where = req.where; |
this.searchFields = req.searchFields; |
this.searchQuery = req.searchQuery; |
this.searchLimit = req.searchLimit; |
this.selTransf = req.selTransf; |
this.lockSelect = req.lockSelect; |
// use methods since they're both lazy |
199,53 → 219,24 |
return casted; |
} |
@Override |
public BaseFillSQLRequest clone() { |
synchronized (this) { |
return this.clone(false); |
} |
} |
// must be called with our lock |
protected abstract BaseFillSQLRequest clone(boolean forFreeze); |
private final SQLRowValues computeGraph() { |
if (this.getFields() == null) |
return null; |
final SQLRowValues vals = new SQLRowValues(this.getPrimaryTable()); |
for (final SQLField f : this.getFields()) { |
vals.put(f.getName(), null); |
} |
this.getShowAs().expand(vals); |
static protected final SQLRowValues computeGraph(final SQLTable t, final Collection<String> fields, final FieldExpander exp) { |
final SQLRowValues vals = new SQLRowValues(t).putNulls(fields); |
exp.expand(vals); |
return vals.toImmutable(); |
} |
/** |
* The graph computed by expanding {@link #getFields()} by {@link #getShowAs()}. |
* The graph with fields to be automatically added to the UI. |
* |
* @return the expanded frozen graph. |
*/ |
public final SQLRowValues getGraph() { |
synchronized (this) { |
if (this.graph == null) { |
assert !this.isFrozen() : "no computation should take place after frozen()"; |
this.graph = this.computeGraph(); |
} |
return this.graph; |
} |
return this.graph; |
} |
// should be called if getFields(), getOrder() or getShowAs() change |
protected final void clearGraph() { |
synchronized (this) { |
checkFrozen(); |
this.graph = null; |
this.graphToFetch = null; |
} |
} |
/** |
* The graph to fetch, should be a superset of {@link #getGraph()}. To modify it, see |
* {@link #addToGraphToFetch(Path, Set)} and {@link #changeGraphToFetch(IClosure)}. |
258,15 → 249,7 |
assert !this.isFrozen() : "no computation should take place after frozen()"; |
final SQLRowValues tmp = this.getGraph().deepCopy(); |
this.customizeToFetch(tmp); |
// fetch order fields, so that consumers can order an updated row in an existing |
// list |
for (final Path orderP : this.getOrder()) { |
final SQLRowValues orderVals = tmp.followPath(orderP); |
if (orderVals != null && orderVals.getTable().isOrdered()) { |
orderVals.put(orderVals.getTable().getOrderField().getName(), null); |
} |
} |
this.graphToFetch = tmp.toImmutable(); |
this.setGraphToFetch(tmp, true); |
} |
return this.graphToFetch; |
} |
296,18 → 279,30 |
public void executeChecked(SQLRowValues input) { |
addToFetch(input, p, fields); |
} |
}); |
}, false); |
} |
public final void changeGraphToFetch(IClosure<SQLRowValues> cl) { |
this.changeGraphToFetch(cl, true); |
} |
private final void changeGraphToFetch(IClosure<SQLRowValues> cl, final boolean checkNeeded) { |
synchronized (this) { |
checkFrozen(); |
final SQLRowValues tmp = this.getGraphToFetch().deepCopy(); |
cl.executeChecked(tmp); |
this.graphToFetch = tmp.toImmutable(); |
this.setGraphToFetch(tmp, checkNeeded); |
} |
fireWhereChange(); |
} |
private final void setGraphToFetch(final SQLRowValues tmp, final boolean checkNeeded) { |
assert Thread.holdsLock(this) && !this.isFrozen(); |
if (checkNeeded && !tmp.graphContains(this.getGraph())) |
throw new IllegalArgumentException("New graph too small"); |
this.graphToFetch = tmp.toImmutable(); |
} |
protected void customizeToFetch(final SQLRowValues graphToFetch) { |
} |
314,9 → 309,18 |
protected synchronized final SQLRowValuesListFetcher getFetcher() { |
if (this.isFrozen()) |
return this.frozen; |
// fetch order fields, so that consumers can order an updated row in an existing list |
final SQLRowValues tmp = getGraphToFetch().deepCopy(); |
for (final Path orderP : this.getOrder()) { |
final SQLRowValues orderVals = tmp.followPath(orderP); |
if (orderVals != null && orderVals.getTable().isOrdered()) { |
orderVals.put(orderVals.getTable().getOrderField().getName(), null); |
} |
} |
// graphToFetch can be modified freely so don't the use the simple constructor |
final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(getGraphToFetch(), false); |
return setupFetcher(fetcher); |
// order to have predictable result (this will both order the referent rows and main rows. |
// The latter will be overwritten by our own getOrder()) |
return setupFetcher(SQLRowValuesListFetcher.create(tmp, true)); |
} |
// allow to pass fetcher since they are mostly immutable (and for huge graphs they are slow to |
342,10 → 346,27 |
return fetcher; |
} |
protected List<Path> getOrder() { |
protected synchronized final List<Path> getOrder() { |
if (this.order != null) |
return this.order; |
return this.getDefaultOrder(); |
} |
protected List<Path> getDefaultOrder() { |
return Collections.singletonList(Path.get(getPrimaryTable())); |
} |
/** |
* Change the ordering of this request. |
* |
* @param l the list of tables, <code>null</code> to restore the {@link #getDefaultOrder() |
* default} . |
*/ |
public synchronized final void setOrder(List<Path> l) { |
checkFrozen(); |
this.order = l == null ? null : Collections.unmodifiableList(new ArrayList<Path>(l)); |
} |
public final void setWhere(final Where w) { |
synchronized (this) { |
checkFrozen(); |
365,9 → 386,14 |
* <code>false</code> to not be searchable. |
*/ |
public final void setSearchable(final boolean b) { |
this.setSearchFields(b ? this.getFields() : Collections.<SQLField> emptyList()); |
this.setSearchFields(b ? getDefaultSearchFields() : Collections.<SearchField> emptyList()); |
} |
protected Collection<SearchField> getDefaultSearchFields() { |
final Set<String> names = CollectionUtils.inter(this.getGraph().getFields(), this.getPrimaryTable().getFieldsNames(VirtualFields.LOCAL_CONTENT)); |
return mapOfModesToSearchFields(CollectionUtils.<String, SQLSearchMode> createMap(names)); |
} |
/** |
* Set the fields used to search. |
* |
374,10 → 400,18 |
* @param searchFields only rows with these fields containing the terms will match. |
* @see #setSearch(String) |
*/ |
public final void setSearchFields(final Collection<SQLField> searchFields) { |
this.setSearchFields(CollectionUtils.<SQLField, SQLSearchMode> createMap(searchFields)); |
public final void setSearchFieldsNames(final Collection<String> searchFields) { |
this.setSearchFieldsNames(CollectionUtils.<String, SQLSearchMode> createMap(searchFields)); |
} |
protected final Collection<SearchField> mapOfModesToSearchFields(Map<String, SQLSearchMode> searchFields) { |
final List<SearchField> list = new ArrayList<SearchField>(); |
for (final Entry<String, SQLSearchMode> e : searchFields.entrySet()) { |
list.add(new SearchField(getPrimaryTable().getField(e.getKey()), e.getValue() == null ? SQLSearchMode.CONTAINS : e.getValue())); |
} |
return list; |
} |
/** |
* Set the fields used to search. |
* |
384,58 → 418,43 |
* @param searchFields for each field to search, how to match. |
* @see #setSearch(String) |
*/ |
public final void setSearchFields(Map<SQLField, SQLSearchMode> searchFields) { |
public final void setSearchFieldsNames(Map<String, SQLSearchMode> searchFields) { |
this.setSearchFields(mapOfModesToSearchFields(searchFields)); |
} |
public final void setSearchFields(final Collection<SearchField> searchFields) { |
// can be outside the synchronized block, since it can't be reverted |
checkFrozen(); |
searchFields = new HashMap<SQLField, SQLSearchMode>(searchFields); |
final Iterator<Entry<SQLField, SQLSearchMode>> iter = searchFields.entrySet().iterator(); |
while (iter.hasNext()) { |
final Entry<SQLField, SQLSearchMode> e = iter.next(); |
if (!String.class.isAssignableFrom(e.getKey().getType().getJavaType())) { |
iter.remove(); |
} else if (e.getValue() == null) { |
e.setValue(SQLSearchMode.CONTAINS); |
} |
final Map<IFieldPath, SearchField> copy = new HashMap<IFieldPath, SearchField>(); |
for (final SearchField f : searchFields) { |
final SearchField prev = copy.put(f.getField(), f); |
if (prev != null) |
throw new IllegalArgumentException("Duplicate : " + f.getField()); |
} |
searchFields = Collections.unmodifiableMap(searchFields); |
synchronized (this) { |
this.searchFields = searchFields; |
this.searchFields = Collections.unmodifiableMap(copy); |
} |
fireWhereChange(); |
} |
public Map<SQLField, SQLSearchMode> getSearchFields() { |
public Map<IFieldPath, SearchField> getSearchFields() { |
synchronized (this) { |
return this.searchFields; |
} |
} |
/** |
* Set the search query. The query will be used to match rows using |
* {@link #setSearchFields(Map)}. I.e. if there's no field set, this method won't have any |
* effect. |
* |
* @param s the search query. |
* @return <code>true</code> if the request changed. |
*/ |
public boolean setSearch(String s) { |
// no need to trim() since trailing empty strings are not returned |
final List<String> split = Arrays.asList(QUERY_SPLIT_PATTERN.split(s)); |
boolean res = false; |
synchronized (this) { |
checkFrozen(); |
if (!split.equals(this.searchQuery)) { |
this.searchQuery = split; |
if (!this.getSearchFields().isEmpty()) { |
res = true; |
} |
} |
} |
if (res) |
this.fireWhereChange(); |
return res; |
public synchronized final boolean isSearchable() { |
return !this.getSearchFields().isEmpty(); |
} |
public synchronized final void setSearchLimit(final int limit) { |
this.searchLimit = limit; |
} |
public synchronized final int getSearchLimit() { |
return this.searchLimit; |
} |
public final synchronized void setLockSelect(boolean lockSelect) { |
checkFrozen(); |
this.lockSelect = lockSelect; |
445,54 → 464,221 |
return this.lockSelect; |
} |
@Override |
public final Collection<SQLField> getAllFields() { |
// don't rely on the expansion of our fields, since our fetcher can be arbitrary modified |
// (eg by adding a where on a field of a non-displayed table) |
return this.getFetcher().getReq().getFields(); |
public Set<SQLTable> getTables() { |
final Set<SQLTable> res = new HashSet<SQLTable>(); |
for (final SQLRowValues v : this.getGraphToFetch().getGraph().getItems()) |
res.add(v.getTable()); |
return res; |
} |
protected abstract Collection<SQLField> getFields(); |
public final void addTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.addTableModifiedListener(l); |
} |
} |
public final void removeTableListener(SQLTableModifiedListener l) { |
for (final SQLTable t : this.getTables()) { |
t.removeTableModifiedListener(l); |
} |
} |
protected final List<SQLField> getFields() { |
return this.getPrimaryTable().getFields(this.getGraph().getFields()); |
} |
protected SQLSelect transformSelect(final SQLSelect sel) { |
final Map<SQLField, SQLSearchMode> searchFields; |
final List<String> searchQuery; |
final ITransformer<SQLSelect, SQLSelect> transf = this.getSelectTransf(); |
return transf == null ? sel : transf.transformChecked(sel); |
} |
// @param searchQuery null means don't want to search in SQL (i.e. no WHERE, no LIMIT), empty |
// means nothing to search (i.e. no WHERE but LIMIT). |
protected final ITransformer<SQLSelect, SQLSelect> createSearchTransformer(final List<String> searchQuery, final Locale l, final Where forceInclude) { |
if (searchQuery == null) |
return null; |
final Map<IFieldPath, SearchField> searchFields; |
final int searchLimit; |
final boolean searchable; |
synchronized (this) { |
searchFields = this.getSearchFields(); |
searchQuery = this.searchQuery; |
searchLimit = this.getSearchLimit(); |
searchable = this.isSearchable(); |
} |
if (!searchable) { |
throw new IllegalArgumentException("Cannot search " + searchQuery); |
} |
// continue even if searchQuery is empty to apply the LIMIT |
final List<String> immutableQuery = Collections.unmodifiableList(new ArrayList<String>(searchQuery)); |
return new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(SQLSelect sel) { |
return transformSelectSearch(sel, searchFields, searchLimit, immutableQuery, l, forceInclude); |
} |
}; |
} |
static protected final SQLSelect transformSelectSearch(final SQLSelect sel, final Map<IFieldPath, SearchField> searchFields, final int searchLimit, final List<String> searchQuery, final Locale l, |
final Where forceInclude) { |
final Where w; |
final Set<String> matchScore = new HashSet<String>(); |
if (!searchFields.isEmpty()) { |
if (!searchQuery.isEmpty()) { |
final SQLSyntax syntax = sel.getSyntax(); |
Where where = null; |
for (final String searchTerm : searchQuery) { |
Where termWhere = null; |
for (final FieldRef selF : sel.getSelectFields()) { |
final SQLSearchMode mode = searchFields.get(selF.getField()); |
if (mode != null) { |
termWhere = Where.createRaw(createWhere(selF, mode, searchTerm)).or(termWhere); |
if (!mode.equals(SQLSearchMode.EQUALS)) |
matchScore.add("case when " + createWhere(selF, SQLSearchMode.EQUALS, searchTerm) + " then 1 else 0 end"); |
for (final SearchField searchField : searchFields.values()) { |
final FieldRef selF = sel.followFieldPath(searchField.getField()); |
final SQLSearchMode mode = searchField.getMode(); |
final List<String> formatted = searchField.format(selF, l); |
final String fieldWhere = createWhere(syntax, formatted, mode, searchTerm); |
termWhere = Where.createRaw(fieldWhere).or(termWhere); |
if (searchField.getScore() > 0 || !searchField.getHigherModes().isEmpty()) { |
final CaseBuilder caseBuilder = syntax.createCaseWhenBuilder().setElse("0"); |
for (final Tuple2<SQLSearchMode, Integer> hm : searchField.getHigherModes()) { |
caseBuilder.addWhen(createWhere(syntax, formatted, hm.get0(), searchTerm), String.valueOf(hm.get1())); |
} |
if (searchField.getScore() > 0) { |
caseBuilder.addWhen(fieldWhere, String.valueOf(searchField.getScore())); |
} |
matchScore.add(caseBuilder.build()); |
} |
} |
where = Where.and(termWhere, where); |
} |
// only use forceInclude when there's a restriction otherwise the include transforms |
// itself into a restrict |
if (where != null) |
where = where.or(forceInclude); |
w = where; |
} else { |
w = null; |
} |
sel.andWhere(w); |
if (forceInclude != null) |
matchScore.add("case when " + forceInclude + " then 10000 else 0 end"); |
if (!matchScore.isEmpty()) |
sel.getOrder().add(0, CollectionUtils.join(matchScore, " + ") + " DESC"); |
if (searchLimit >= 0) |
sel.setLimit(searchLimit); |
final ITransformer<SQLSelect, SQLSelect> transf = this.getSelectTransf(); |
return transf == null ? sel : transf.transformChecked(sel); |
return sel; |
} |
protected String createWhere(final FieldRef selF, final SQLSearchMode mode, final String searchQuery) { |
return "lower(" + selF.getFieldRef() + ") " + mode.generateSQL(selF.getField().getDBRoot(), searchQuery.toLowerCase()); |
static protected final String createWhere(final SQLSyntax syntax, final List<String> formatted, final SQLSearchMode mode, final String searchQuery) { |
return CollectionUtils.join(formatted, " OR ", new ITransformer<String, String>() { |
@Override |
public String transformChecked(String sqlExpr) { |
return createWhere(sqlExpr, mode, syntax, searchQuery); |
} |
}); |
} |
static public final List<String> defaultFormat(final FieldRef selF, final Locale l) { |
final SQLType type = selF.getField().getType(); |
final SQLSyntax syntax = SQLSyntax.get(selF.getField()); |
if (type.getJavaType() == String.class) { |
return Collections.singletonList(selF.getFieldRef()); |
} else if (type.getJavaType() == Boolean.class) { |
return Collections.singletonList("case when " + selF.getFieldRef() + " then " + syntax.quoteString(TM.tr("true_key")) + " else " + syntax.quoteString(TM.tr("false_key")) + " end"); |
} else if (Timestamp.class.isAssignableFrom(type.getJavaType())) { |
final String shortFmt = formatTime(selF, DateProp.SHORT_DATETIME_SKELETON, l, syntax); |
final String longFmt = formatTime(selF, DateProp.LONG_DATETIME_SKELETON, l, syntax); |
return Arrays.asList(shortFmt, longFmt); |
} else if (Time.class.isAssignableFrom(type.getJavaType())) { |
return Collections.singletonList(formatTime(selF, DateProp.TIME_SKELETON, l, syntax)); |
} else if (Date.class.isAssignableFrom(type.getJavaType())) { |
final String shortFmt = formatTime(selF, DateProp.SHORT_DATE_SKELETON, l, syntax); |
final String longFmt = formatTime(selF, DateProp.LONG_DATE_SKELETON, l, syntax); |
return Arrays.asList(shortFmt, longFmt); |
} else { |
return Collections.singletonList(syntax.cast(selF.getFieldRef(), String.class)); |
} |
} |
static public final String formatTime(final FieldRef selF, final List<String> simpleFormat, final Locale l, final SQLSyntax syntax) { |
return syntax.getFormatTimestampSimple(selF.getFieldRef(), DateProp.getBestPattern(simpleFormat, l), l); |
} |
static protected final String createWhere(final String sqlExpr, final SQLSearchMode mode, final SQLSyntax syntax, final String searchQuery) { |
return "lower(" + sqlExpr + ") " + mode.generateSQL(syntax, searchQuery.toLowerCase()); |
} |
static public class SearchField { |
private final IFieldPath field; |
private final SQLSearchMode mode; |
private final int score; |
private final List<Tuple2<SQLSearchMode, Integer>> higherModes; |
public SearchField(IFieldPath field, SQLSearchMode mode) { |
this(field, mode, 1); |
} |
/** |
* Create a new search field. |
* |
* @param field which field to search. |
* @param mode how to search. |
* @param score the score (>0) to attribute if the field matches. Allow to rank fields |
* between themselves. |
*/ |
public SearchField(IFieldPath field, SQLSearchMode mode, int score) { |
this(field, mode, score, -1, -1); |
} |
public SearchField(final IFieldPath field, final SQLSearchMode mode, final int score, final int score2, final int score3) { |
super(); |
if (field.getField().getFieldGroup().getKeyType() != null) |
throw new IllegalArgumentException("Field is a key : " + field); |
this.field = field; |
this.mode = mode; |
/* |
* for now we could pass <code>1</code> so that a row with more matches is higher ranked |
* (e.g. if searching "a" ["ant", "cat"] is better than ["ant", "horse"]), or |
* <code>0</code> to ignore the match count. But this only works because we have |
* separate WHERE and ORDER BY ; if we had a computed column with "WHERE score > 0 ORDER |
* BY score" this would be complicated. |
*/ |
if (score < 1) |
throw new IllegalArgumentException("Invalid score : " + score); |
this.score = score; |
final List<SQLSearchMode> higherModes = field.getField().getType().getJavaType() == String.class ? this.mode.getHigherModes() : Collections.<SQLSearchMode> emptyList(); |
if (higherModes.isEmpty()) { |
this.higherModes = Collections.emptyList(); |
} else { |
if (higherModes.size() > 2) |
throw new IllegalStateException("Too many higher modes " + higherModes); |
final List<Tuple2<SQLSearchMode, Integer>> tmp = new ArrayList<Tuple2<SQLSearchMode, Integer>>(2); |
tmp.add(Tuple2.create(higherModes.get(0), score3 < 1 ? Math.max((int) (this.score * 1.5), this.score + 2) : score3)); |
if (higherModes.size() > 1) |
tmp.add(Tuple2.create(higherModes.get(1), score2 < 1 ? Math.max((int) (this.score * 1.2), this.score + 1) : score2)); |
this.higherModes = Collections.unmodifiableList(tmp); |
} |
} |
public final IFieldPath getField() { |
return this.field; |
} |
public final SQLSearchMode getMode() { |
return this.mode; |
} |
public final int getScore() { |
return this.score; |
} |
public List<Tuple2<SQLSearchMode, Integer>> getHigherModes() { |
return this.higherModes; |
} |
protected List<String> format(final FieldRef selF, final Locale l) { |
if (getField().getField() != selF.getField()) |
throw new IllegalArgumentException("Wrong field"); |
return defaultFormat(selF, l); |
} |
} |
public final synchronized ITransformer<SQLSelect, SQLSelect> getSelectTransf() { |
return this.selTransf; |
} |
510,8 → 696,6 |
this.fireWhereChange(); |
} |
protected abstract FieldExpander getShowAs(); |
public final SQLTable getPrimaryTable() { |
return this.primaryTable; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/request/SQLFieldTranslator.java |
---|
52,14 → 52,14 |
import java.util.Set; |
import java.util.prefs.Preferences; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.ThreadSafe; |
import org.jdom2.Document; |
import org.jdom2.Element; |
import org.jdom2.JDOMException; |
import org.jdom2.input.SAXBuilder; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.ThreadSafe; |
/** |
* Class to obtain a RowItemDesc from a table and a name. |
* |
149,21 → 149,12 |
this.unknownCodes = new HashSet<String>(); |
} |
public SQLFieldTranslator(DBRoot base) { |
this(base, null); |
} |
public SQLFieldTranslator(DBRoot base, InputStream inputStream) { |
this(base, inputStream, null); |
} |
/** |
* Create a new instance. |
* |
* @param root the default root for tables. |
* @param inputStream the XML, can be <code>null</code>. |
* @param dir the directory where to look for tables not in <code>root</code>, can be |
* <code>null</code>. |
* @param dir the directory where to look for tables not in <code>root</code>. |
*/ |
public SQLFieldTranslator(DBRoot root, InputStream inputStream, SQLElementDirectory dir) { |
try { |
194,6 → 185,10 |
fetchAndPut(this.table, null); |
} |
public final SQLElementDirectory getDirectory() { |
return this.dir; |
} |
/** |
* Add all translations of <code>o</code> to this, note that if a table is present in both this |
* and <code>o</code> its translations won't be changed. |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java |
---|
18,6 → 18,7 |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.FieldExpander; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.PropsConfiguration; |
import org.openconcerto.sql.TM; |
import org.openconcerto.sql.element.SQLElementLink.LinkType; |
import org.openconcerto.sql.element.TreesOfSQLRows.LinkToCut; |
56,23 → 57,29 |
import org.openconcerto.sql.request.SQLCache; |
import org.openconcerto.sql.request.SQLFieldTranslator; |
import org.openconcerto.sql.sqlobject.SQLTextCombo; |
import org.openconcerto.sql.ui.light.ConvertorModifer; |
import org.openconcerto.sql.ui.light.GroupToLightUIConvertor; |
import org.openconcerto.sql.ui.light.LightEditFrame; |
import org.openconcerto.sql.ui.light.LightUIPanelFiller; |
import org.openconcerto.sql.ui.light.SavableCustomEditorProvider; |
import org.openconcerto.sql.users.rights.UserRightsManager; |
import org.openconcerto.sql.utils.SQLUtils; |
import org.openconcerto.sql.utils.SQLUtils.SQLFactory; |
import org.openconcerto.sql.view.EditFrame; |
import org.openconcerto.sql.view.EditPanel.EditMode; |
import org.openconcerto.sql.view.list.IListeAction; |
import org.openconcerto.sql.view.list.SQLTableModelColumn; |
import org.openconcerto.sql.view.list.SQLTableModelColumnPath; |
import org.openconcerto.sql.view.list.SQLTableModelSource; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOffline; |
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline; |
import org.openconcerto.ui.group.Group; |
import org.openconcerto.ui.light.ColumnsSpec; |
import org.openconcerto.ui.light.ComboValueConvertor; |
import org.openconcerto.ui.light.CustomEditorProvider; |
import org.openconcerto.ui.light.IntValueConvertor; |
import org.openconcerto.ui.light.LightUIComboBox; |
import org.openconcerto.ui.light.LightUIComboBoxElement; |
import org.openconcerto.ui.light.LightUIElement; |
import org.openconcerto.ui.light.Row; |
import org.openconcerto.ui.light.LightUIFrame; |
import org.openconcerto.ui.light.LightUIPanel; |
import org.openconcerto.ui.light.StringValueConvertor; |
import org.openconcerto.utils.CollectionMap2Itf.SetMapItf; |
import org.openconcerto.utils.CollectionUtils; |
274,46 → 281,113 |
} |
/** |
* Create a Row to put in a TableContent |
* Get the group based on the edit mode |
* |
* @param sqlRow SQLRowValues used to create the Row |
* @param allCols Columns attach to this SQLElement |
* @param columnsSpec Columns of the LightUITable attach to this SQLElement |
* @param editMode |
* @return |
*/ |
public Group getEditGroup(final EditMode editMode) { |
if (editMode.equals(EditMode.CREATION)) { |
return this.getGroupForCreation(); |
} else { |
return this.getGroupForModification(); |
} |
} |
/** |
* Override this function in an element to show default values in edit frame |
* |
* @return New Row created from the SQLRowValues |
* @param token - The security token of session |
* |
* @return a default SQLRowValues |
*/ |
public final Row createRowFromSQLRow(final SQLRowValues sqlRow, final List<SQLTableModelColumn> allCols, final ColumnsSpec columnsSpec) { |
final Row row = new Row(sqlRow.getID()); |
public SQLRowValues createDefaultRowValues(final String token) { |
return new SQLRowValues(getTable()); |
} |
final List<Object> values = new ArrayList<Object>(); |
final int colSize = allCols.size(); |
for (int i = 0; i < colSize; i++) { |
final String columnId = columnsSpec.getColumn(i).getId(); |
final SQLTableModelColumn col = getColumnFromId(allCols, columnId); |
this.configureConverter(col); |
if (col != null) { |
Object value = col.show(sqlRow); |
if (col.getLightUIrenderer() != null) { |
value = col.getLightUIrenderer().getLightUIElement(value, 0, i); |
} |
values.add(value); |
} else { |
throw new IllegalArgumentException("column " + columnId + " is in ColumnsSpec but it is not found in SQLTableModelColumn"); |
} |
/** |
* Create the edition frame for this SQLElement |
* |
* @param configuration current configuration |
* @param parentFrame parent frame of the edit frame |
* @param editMode edition mode (CREATION, MODIFICATION, READONLY) |
* @param sqlRow SQLRowAccessor use for fill the edition frame |
* @param sessionSecurityToken String, use for find session with an instance of LightServer |
* @return the edition frame of this SQLElement |
*/ |
public LightEditFrame createEditFrame(final PropsConfiguration configuration, final LightUIFrame parentFrame, final EditMode editMode, final SQLRowAccessor sqlRow, |
final String sessionSecurityToken) { |
final Group editGroup = this.getEditGroup(editMode); |
if (editGroup == null) { |
Log.get().severe("The edit group is null for this element : " + this); |
return null; |
} |
row.setValues(values); |
return row; |
final GroupToLightUIConvertor convertor = this.getGroupToLightUIConvertor(configuration, editMode, sqlRow, sessionSecurityToken); |
final LightEditFrame editFrame = convertor.convert(editGroup, sqlRow, parentFrame, editMode); |
if (editMode.equals(EditMode.CREATION)) { |
editFrame.createTitlePanel(this.getCreationFrameTitle()); |
} else if (editMode.equals(EditMode.MODIFICATION)) { |
editFrame.createTitlePanel(this.getModificationFrameTitle(sqlRow)); |
new LightUIPanelFiller(editFrame.getFirstChild(LightUIPanel.class)).fillFromRow(configuration, sqlRow); |
} else if (editMode.equals(EditMode.READONLY)) { |
editFrame.createTitlePanel(this.getReadOnlyFrameTitle(sqlRow)); |
new LightUIPanelFiller(editFrame.getFirstChild(LightUIPanel.class)).fillFromRow(configuration, sqlRow); |
} |
this.setEditFrameModifiers(editFrame, sessionSecurityToken); |
return editFrame; |
} |
public final SQLTableModelColumn getColumnFromId(final List<SQLTableModelColumn> allCols, final String columnId) { |
final int columnSize = allCols.size(); |
for (int i = 0; i < columnSize; i++) { |
final SQLTableModelColumn tableModelColumn = allCols.get(i); |
if (tableModelColumn.getIdentifier().equals(columnId)) { |
return tableModelColumn; |
} |
/** |
* Get title for read only mode |
* |
* @param sqlRow - SQLRowValues use for fill the edition frame |
* @return The title for read only mode |
*/ |
protected String getReadOnlyFrameTitle(final SQLRowAccessor sqlRow) { |
return EditFrame.getReadOnlyMessage(this); |
} |
/** |
* Get title for modification mode |
* |
* @param sqlRow - SQLRowValues use for fill the edition frame |
* @return The title for read only mode |
*/ |
protected String getModificationFrameTitle(final SQLRowAccessor sqlRow) { |
return EditFrame.getModifyMessage(this); |
} |
/** |
* Get title for creation mode |
* |
* @param sqlRow - SQLRowValues use for fill the edition frame |
* @return The title for read only mode |
*/ |
protected String getCreationFrameTitle() { |
return EditFrame.getCreateMessage(this); |
} |
/** |
* |
* @param configuration - The user SQL configuration |
* @param editMode - Edit mode of the frame |
* @param sqlRow - The row to update |
* @param token - The session security token |
* |
* @return An initialized GroupToLightUIConvertor |
*/ |
public GroupToLightUIConvertor getGroupToLightUIConvertor(final PropsConfiguration configuration, final EditMode editMode, final SQLRowAccessor sqlRow, final String token) { |
final GroupToLightUIConvertor convertor = new GroupToLightUIConvertor(configuration); |
if (editMode.equals(EditMode.CREATION)) { |
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForCreation(configuration, token)); |
} else { |
convertor.putAllCustomEditorProvider(this.getCustomEditorProviderForModification(configuration, sqlRow, token)); |
} |
return null; |
return convertor; |
} |
/** |
323,7 → 397,7 |
* @return Map which contains all ComboValueConvertors use for this SQLElement edition. Key: ID |
* of group item / Value: ComboValueConvertor |
*/ |
// FIXME: voir avec Sylvain pour les conversions |
// TODO: use renderer instead of ValueConvertor |
public Map<String, ComboValueConvertor<?>> getComboConvertors() { |
return new HashMap<String, ComboValueConvertor<?>>(); |
} |
332,81 → 406,167 |
* Override this function in an element and put new value in map for use ConvertorModifier. This |
* one allow you to apply some change on LightUIElement before send it to client |
* |
* @return Map which contains all ConvertorModifier use for this SQLElement edition. Key: ID of |
* group item / Value: ConvertorModeifier |
*/ |
public Map<String, ConvertorModifer> getConvertorModifiers() { |
return new HashMap<String, ConvertorModifer>(); |
// TODO: implement with IClosure |
public void setEditFrameModifiers(final LightEditFrame frame, final String sessionToken) { |
} |
public Map<String, CustomEditorProvider> getCustomEditorProviderForCreation(final Configuration configuration, final long userId) { |
return this.getDefaultCustomEditorProvider(configuration, null, userId); |
public final Map<String, CustomEditorProvider> getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) { |
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, null, sessionToken); |
map.putAll(this._getCustomEditorProviderForCreation(configuration, sessionToken)); |
return map; |
} |
public Map<String, CustomEditorProvider> getCustomEditorProviderForModification(final Configuration configuration, final SQLRowValues sqlRow, final long userId) { |
return this.getDefaultCustomEditorProvider(configuration, sqlRow, userId); |
public final Map<String, CustomEditorProvider> getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) { |
final Map<String, CustomEditorProvider> map = this.getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken); |
map.putAll(this._getCustomEditorProviderForModification(configuration, sqlRow, sessionToken)); |
return map; |
} |
protected Map<String, CustomEditorProvider> getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowValues sqlRow, final long userId) { |
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForCreation(final Configuration configuration, final String sessionToken) { |
return new HashMap<String, CustomEditorProvider>(); |
} |
protected Map<String, CustomEditorProvider> _getCustomEditorProviderForModification(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) { |
return new HashMap<String, CustomEditorProvider>(); |
} |
protected Map<String, CustomEditorProvider> _getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) { |
return new HashMap<String, CustomEditorProvider>(); |
} |
private final Map<String, CustomEditorProvider> getDefaultCustomEditorProvider(final Configuration configuration, final SQLRowAccessor sqlRow, final String sessionToken) { |
final Map<String, ComboValueConvertor<?>> comboConvertors = this.getComboConvertors(); |
final Map<String, CustomEditorProvider> result = new HashMap<String, CustomEditorProvider>(); |
for (final Entry<String, ComboValueConvertor<?>> entry : comboConvertors.entrySet()) { |
result.put(entry.getKey(), new CustomEditorProvider() { |
result.put(entry.getKey(), new SavableCustomEditorProvider() { |
final ComboValueConvertor<?> convertor = entry.getValue(); |
@Override |
public LightUIElement createUIElement(final String elementId) { |
final LightUIComboBox uiCombo = new LightUIComboBox(elementId); |
this.convertor.fillCombo(uiCombo); |
if (sqlRow != null) { |
if (sqlRow == null) { |
this.convertor.fillCombo(uiCombo, null); |
} else { |
final SQLField field = configuration.getFieldMapper().getSQLFieldForItem(elementId); |
LightUIComboBoxElement selectedValue = null; |
if (this.convertor instanceof StringValueConvertor) { |
final StringValueConvertor stringConvertor = (StringValueConvertor) this.convertor; |
final String value = sqlRow.getString(field.getFieldName()); |
if (value != null) { |
selectedValue = new LightUIComboBoxElement(stringConvertor.getIndexFromId(value)); |
selectedValue.setValue1(stringConvertor.convert(value)); |
} |
((StringValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getString(field.getFieldName())); |
} else if (this.convertor instanceof IntValueConvertor) { |
final IntValueConvertor intConvertor = (IntValueConvertor) this.convertor; |
if (sqlRow.getObject(field.getFieldName()) != null) { |
final int value = sqlRow.getInt(field.getFieldName()); |
selectedValue = new LightUIComboBoxElement(value); |
selectedValue.setValue1(intConvertor.convert(value)); |
if (sqlRow.getObject(field.getFieldName()) == null) { |
this.convertor.fillCombo(uiCombo, null); |
} else { |
((IntValueConvertor) this.convertor).fillCombo(uiCombo, sqlRow.getInt(field.getFieldName())); |
} |
} |
uiCombo.setSelectedValue(selectedValue); |
} |
return uiCombo; |
} |
@Override |
protected void _save(final SQLRowValues sqlRow, final SQLField sqlField, final LightUIElement uiElement) { |
final LightUIComboBox combo = (LightUIComboBox) uiElement; |
if (combo.hasSelectedValue()) { |
if (this.convertor instanceof StringValueConvertor) { |
sqlRow.put(sqlField.getName(), ((StringValueConvertor) this.convertor).getIdFromIndex(combo.getSelectedValue().getId())); |
} else if (this.convertor instanceof IntValueConvertor) { |
sqlRow.put(sqlField.getName(), combo.getSelectedValue().getId()); |
} else { |
throw new IllegalArgumentException("the save is not implemented for the class: " + this.convertor.getClass().getName() + " - ui element id: " + uiElement.getId()); |
} |
} else { |
sqlRow.put(sqlField.getName(), null); |
} |
} |
}); |
} |
result.putAll(this._getDefaultCustomEditorProvider(configuration, sqlRow, sessionToken)); |
return result; |
} |
/** |
* Add value converter on a SQLTableModelColumn to change the attached value in SQLRowValues |
* when createRowFromRowValues is called |
* Override this function in an element to execute some code just after inserted new row in |
* database |
* |
* @param editFrame - The edit frame of this SQLRow |
* @param sqlRow - The row which was just inserted |
* @param sessionToken Security token of session which allow to find session in LightServer |
* instance |
* |
* @param col SQLTableModelColumn that you want change the value |
* @throws Exception |
*/ |
protected void configureConverter(final SQLTableModelColumn col) { |
public void doAfterLightInsert(final LightEditFrame editFrame, final SQLRow sqlRow, final String sessionToken) throws Exception { |
} |
/** |
* Override this function in an element to execute some code just after inserted new row in |
* Override this function in an element to execute some code just after deleted a row in |
* database |
* |
* @param frame - The current frame |
* @param sqlRow - The row which was deleted |
* @param sessionToken Security token of session which allow to find session in LightServer |
* instance |
* |
* @param row The row which was just inserted |
* @throws Exception |
*/ |
public void doAfterLightInsert(SQLRow row) { |
public void doAfterLightDelete(final LightUIFrame frame, final SQLRowValues sqlRow, final String sessionToken) throws Exception { |
} |
/** |
* Override this function in an element to execute some code before inserted new row in database |
* |
* @param frame - The current frame |
* @param sqlRow - The row which will be deleted |
* @param sessionToken - Security token of session which allow to find session in LightServer |
* instance |
* |
* @throws Exception |
*/ |
public void doBeforeLightDelete(final LightUIFrame frame, final SQLRowValues sqlRow, final String sessionToken) throws Exception { |
} |
/** |
* Override this function in an element to execute some code before inserted new row in database |
* |
* @param editFrame - The edit frame of this SQLRowValues |
* @param sqlRow - The row which was just inserted |
* @param sessionToken - Security token of session which allow to find session in LightServer |
* instance |
* |
* @throws Exception |
*/ |
public void doBeforeLightInsert(final LightEditFrame editFrame, final SQLRowValues sqlRow, final String sessionToken) throws Exception { |
} |
/** |
* Get ShowAs values of this SQLElement |
* |
* @param id - The id which you want to expand |
* |
* @return A SQLRowValues with data |
*/ |
public SQLRowValues getValuesOfShowAs(final Number id) { |
final SQLRowValues tmp = new SQLRowValues(this.getTable()); |
final ListMap<String, String> showAs = this.getShowAs(); |
for (final List<String> listStr : showAs.values()) { |
tmp.putNulls(listStr); |
} |
this.getDirectory().getShowAs().expand(tmp); |
final SQLRowValues fetched = SQLRowValuesListFetcher.create(tmp).fetchOne(id); |
if (fetched == null) { |
throw new IllegalArgumentException("Impossible to find Row in database - table: " + this.getTable().getName() + ", id: " + id); |
} |
return fetched; |
} |
/** |
* Must be called if foreign/referent keys are added or removed. |
*/ |
public synchronized void resetRelationships() { |
416,8 → 576,8 |
l.getOwned().resetRelationshipsOf(this); |
} |
} |
this.ownedLinks = this instanceof JoinSQLElement ? new SQLElementLinks(SetMap.<LinkType, SQLElementLink>empty()) : null; |
this.otherLinks = this instanceof JoinSQLElement ? new SQLElementLinks(SetMap.<LinkType, SQLElementLink>empty()) : null; |
this.ownedLinks = this instanceof JoinSQLElement ? new SQLElementLinks(SetMap.<LinkType, SQLElementLink> empty()) : null; |
this.otherLinks = this instanceof JoinSQLElement ? new SQLElementLinks(SetMap.<LinkType, SQLElementLink> empty()) : null; |
this.parentFF = null; |
} |
758,7 → 918,7 |
} |
public final UpdateScript update(final SQLRowValues from, final SQLRowValues to, final boolean allowedToChangeTo) { |
return this.update(from, to, allowedToChangeTo, Transformer.<SQLRowValues>nopTransformer()); |
return this.update(from, to, allowedToChangeTo, Transformer.<SQLRowValues> nopTransformer()); |
} |
private final UpdateScript update(final SQLRowValues from, SQLRowValues to, boolean allowedToChangeTo, ITransformer<SQLRowValues, SQLRowValues> copy2originalRows) { |
1581,10 → 1741,19 |
} |
} |
protected ComboSQLRequest createComboRequest() { |
return new ComboSQLRequest(this.getTable(), this.getComboFields()); |
public final ComboSQLRequest createComboRequest() { |
return this.createComboRequest(null, null); |
} |
public final ComboSQLRequest createComboRequest(final List<String> fields, final Where w) { |
final ComboSQLRequest res = new ComboSQLRequest(this.getTable(), fields == null ? this.getComboFields() : fields, w, this.getDirectory()); |
this._initComboRequest(res); |
return res; |
} |
protected void _initComboRequest(final ComboSQLRequest req) { |
} |
// not all elements need to be displayed in combos so don't make this method abstract |
protected List<String> getComboFields() { |
return this.getListFields(); |
1668,35 → 1837,46 |
public final synchronized SQLTableModelSourceOnline getTableSource(final boolean create) { |
if (!create) { |
if (this.tableSrc == null) { |
this.tableSrc = createAndInitTableSource(); |
this.tableSrc = createTableSource(); |
} |
return this.tableSrc; |
} else |
return this.createAndInitTableSource(); |
return this.createTableSource(); |
} |
public final SQLTableModelSourceOnline createTableSource() { |
return createTableSource((Where) null); |
} |
public final SQLTableModelSourceOnline createTableSource(final List<String> fields) { |
return initTableSource(new SQLTableModelSourceOnline(createListRequest(fields))); |
return createTableSourceOnline(createListRequest(fields)); |
} |
public final SQLTableModelSourceOnline createTableSource(final Where w) { |
final SQLTableModelSourceOnline res = this.getTableSource(true); |
res.getReq().setWhere(w); |
return res; |
return createTableSourceOnline(createListRequest(null, w, null)); |
} |
private final SQLTableModelSourceOnline createAndInitTableSource() { |
final SQLTableModelSourceOnline res = this.createTableSource(); |
res.getColumns().addAll(this.additionalListCols); |
return initTableSource(res); |
public final SQLTableModelSourceOnline createTableSourceOnline(final ListSQLRequest req) { |
return initTableSource(instantiateTableSourceOnline(req)); |
} |
protected synchronized void _initTableSource(final SQLTableModelSourceOnline res) { |
protected SQLTableModelSourceOnline instantiateTableSourceOnline(final ListSQLRequest req) { |
return new SQLTableModelSourceOnline(req, this); |
} |
public final synchronized SQLTableModelSourceOnline initTableSource(final SQLTableModelSourceOnline res) { |
protected synchronized void _initTableSource(final SQLTableModelSource res) { |
if (!this.additionalListCols.isEmpty()) |
res.getColumns().addAll(this.additionalListCols); |
} |
public final <S extends SQLTableModelSource> S initTableSource(final S res) { |
return this.initTableSource(res, false); |
} |
public final synchronized <S extends SQLTableModelSource> S initTableSource(final S res, final boolean minimal) { |
// do init first since it can modify the columns |
this._initTableSource(res); |
if (!minimal) |
this._initTableSource(res); |
// setEditable(false) on read only fields |
// MAYBE setReadOnlyFields() on SQLTableModelSource, so that SQLTableModelLinesSource can |
// check in commit() |
1708,12 → 1888,22 |
return res; |
} |
protected SQLTableModelSourceOnline createTableSource() { |
// also create a new ListSQLRequest, otherwise it's a backdoor to change the behaviour of |
// the new TableModelSource |
return new SQLTableModelSourceOnline(this.createListRequest()); |
public final SQLTableModelSourceOffline createTableSourceOffline() { |
return createTableSourceOfflineWithWhere(null); |
} |
public final SQLTableModelSourceOffline createTableSourceOfflineWithWhere(final Where w) { |
return createTableSourceOffline(createListRequest(null, w, null)); |
} |
public final SQLTableModelSourceOffline createTableSourceOffline(final ListSQLRequest req) { |
return initTableSource(instantiateTableSourceOffline(req)); |
} |
protected SQLTableModelSourceOffline instantiateTableSourceOffline(final ListSQLRequest req) { |
return new SQLTableModelSourceOffline(req, this); |
} |
/** |
* Whether to cache our tableSource. |
* |
2287,7 → 2477,7 |
if (parentLink.isJoin()) { |
sel.addSelect(joinPK, null, "joinID"); |
} else { |
sel.addRawSelect(syntax.cast("NULL", joinPK.getTypeDecl()), "joinID"); |
sel.addRawSelect(syntax.cast("NULL", joinPK.getType()), "joinID"); |
} |
sel.addRawSelect(String.valueOf(listIter.previousIndex()), "fieldIndex"); |
sel.setArchivedPolicy(archiveMode); |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java |
---|
24,8 → 24,6 |
import org.openconcerto.sql.model.SQLRow; |
import org.openconcerto.sql.model.SQLRowAccessor; |
import org.openconcerto.sql.model.SQLRowValues; |
import org.openconcerto.sql.model.SQLRowValuesListFetcher; |
import org.openconcerto.sql.model.SQLSelect; |
import org.openconcerto.sql.model.SQLSelect.LockStrength; |
import org.openconcerto.sql.model.SQLType; |
import org.openconcerto.sql.request.MutableRowItemView; |
740,9 → 738,6 |
} |
public void select(SQLRowAccessor r, Set<String> views) { |
// FIXME force loading |
if (r instanceof SQLRow) |
((SQLRow) r).exists(); |
try { |
// allow null to pass, ease some code (eg new ListOfSomething().getTable() even if we |
// can't see the table) |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLComponent.java |
---|
52,7 → 52,7 |
final AlterTable res = new AlterTable(t); |
if (!t.contains(READ_ONLY_FIELD)) { |
// writable by default |
res.addColumn(READ_ONLY_FIELD, "varchar(16) default " + t.getBase().quoteString(READ_WRITE_VALUE) + " NOT NULL"); |
res.addVarCharColumn(READ_ONLY_FIELD, 16, false, res.getSyntax().quoteString(READ_WRITE_VALUE), false); |
res.addForeignColumn(READ_ONLY_USER_FIELD, UserManager.getInstance().getTable()); |
} |
return res; |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElementDirectory.java |
---|
20,6 → 20,7 |
import org.openconcerto.sql.model.DBStructureItemNotFound; |
import org.openconcerto.sql.model.SQLName; |
import org.openconcerto.sql.model.SQLTable; |
import org.openconcerto.sql.request.SQLFieldTranslator; |
import org.openconcerto.utils.CollectionMap2; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.SetMap; |
43,6 → 44,8 |
import org.jdom2.JDOMException; |
import net.jcip.annotations.GuardedBy; |
/** |
* Directory of SQLElement by table. |
* |
82,6 → 85,8 |
private String phrasesPkgName; |
private final Map<String, SQLElementNames> elementNames; |
@GuardedBy("this") |
private SQLFieldTranslator translator; |
private final ShowAs showAs; |
public SQLElementDirectory() { |
104,6 → 109,16 |
return this.showAs; |
} |
public final synchronized void setTranslator(SQLFieldTranslator translator) { |
if (translator.getDirectory() != this) |
throw new IllegalArgumentException("Not for this : " + translator); |
this.translator = translator; |
} |
public synchronized final SQLFieldTranslator getTranslator() { |
return this.translator; |
} |
private static <K> SQLTable getSoleTable(SetMap<K, SQLTable> m, K key) throws IllegalArgumentException { |
final Collection<SQLTable> res = m.getNonNull(key); |
if (res.size() > 1) |
121,6 → 136,7 |
if (!this.contains(elem.getTable())) |
this.addSQLElement(elem); |
} |
this.translator.putAll(o.getTranslator()); |
} |
/** |
/trunk/OpenConcerto/src/org/openconcerto/sql/element/GroupSQLComponent.java |
---|
60,6 → 60,8 |
public class GroupSQLComponent extends BaseSQLComponent { |
public static final String ITEM_RIGHT_CODE = "GROUP_ITEM_SHOW"; |
private final Group group; |
private final int columns = 2; |
private final Map<String, JComponent> labels = new HashMap<String, JComponent>(); |
462,8 → 464,8 |
JComponent label = this.labels.get(id); |
if (label == null) { |
label = createLabel(id); |
if (!UserRightsManager.getCurrentUserRights().haveRight("GROUP_ITEM_SHOW", id) |
|| !UserRightsManager.getCurrentUserRights().haveRight("GROUP_ITEM_SHOW", getElement().getTable().getName() + "." + id)) { |
if (!UserRightsManager.getCurrentUserRights().haveRight(ITEM_RIGHT_CODE, id) |
|| !UserRightsManager.getCurrentUserRights().haveRight(ITEM_RIGHT_CODE, getElement().getTable().getName() + "." + id)) { |
label.setVisible(false); |
} |
475,7 → 477,7 |
return label; |
} |
private RowItemDesc getRIVDescForId(final String id) { |
public RowItemDesc getRIVDescForId(final String id) { |
if (TranslationManager.getInstance().getLocale() != null) { |
final String t = TranslationManager.getInstance().getTranslationForItem(id); |
if (t != null) { |
501,8 → 503,8 |
JComponent editor = this.editors.get(id); |
if (editor == null) { |
editor = createEditor(id); |
if (!UserRightsManager.getCurrentUserRights().haveRight("GROUP_ITEM_SHOW", id) |
|| !UserRightsManager.getCurrentUserRights().haveRight("GROUP_ITEM_SHOW", getElement().getTable().getName() + "." + id)) { |
if (!UserRightsManager.getCurrentUserRights().haveRight(ITEM_RIGHT_CODE, id) |
|| !UserRightsManager.getCurrentUserRights().haveRight(ITEM_RIGHT_CODE, getElement().getTable().getName() + "." + id)) { |
editor.setVisible(false); |
} |
this.editors.put(id, editor); |
/trunk/OpenConcerto/src/org/openconcerto/sql/navigator/SQLBrowser.java |
---|
392,8 → 392,8 |
} |
/** |
* The selected rows of the last column which restricts the browser selection. Eg if the last |
* column has "ALL" selected, return the selection of the previous column. |
* The selected rows of the last column which restricts the browser selection. E.g. if the last |
* column has "ALL" selected, return the selection of the previous column (except if searched). |
* |
* @return the last meaningful selection. |
*/ |
403,21 → 403,25 |
} |
/** |
* The selected rows of all columns with meaningful selection, ie not ALL (except if searched) |
* and not empty. |
* The selected rows of the last column with a {@link #getLastMeaningfullRows() meaningful |
* selection} and after that all of their ancestors. |
* |
* @return the selected rows of all columns. |
* @return the selected rows and their ancestors, the root of the hierarchy last. |
*/ |
public List<Set<SQLRow>> getMeaningfullRows() { |
final SQLBrowserColumn<?, ?> col = getLastMeaningfullCol(); |
if (col == null) |
if (col == null) { |
return Collections.<Set<SQLRow>> emptyList(); |
else { |
} else { |
final List<Set<SQLRow>> res = new ArrayList<Set<SQLRow>>(); |
res.add(new HashSet<SQLRow>(col.getUserSelectedRows())); |
SQLBrowserColumn<?, ?> c = col.previousRowsColumn(); |
while (c != null) { |
res.add(c.getModel().getHighlighted()); |
// Use getHighlighted() instead of getUserSelectedRows() as we want ancestors, e.g. |
// we don't want ALL but only the parent of the selection. |
// highlighted becomes empty if the user selects a highlighted row. |
final Set<SQLRow> highlighted = c.getModel().getHighlighted(); |
res.add(!highlighted.isEmpty() ? highlighted : new HashSet<SQLRow>(c.getUserSelectedRows())); |
c = c.previousRowsColumn(); |
} |
return res; |
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_en.properties |
---|
129,6 → 129,9 |
infoPanel.dirs=Folders |
infoPanel.logs=Logs |
infoPanel.docs=Documents |
infoPanel.dataDir=Data |
infoPanel.prefsDir=Preferences |
infoPanel.cacheDir=Cache |
infoPanel.softwareTitle=Software |
infoPanel.systemTitle=System information |
/trunk/OpenConcerto/src/org/openconcerto/sql/translation/messages_fr.properties |
---|
130,6 → 130,9 |
infoPanel.dirs=Dossiers |
infoPanel.logs=Journaux |
infoPanel.docs=Documents |
infoPanel.dataDir=Données |
infoPanel.prefsDir=Préférences |
infoPanel.cacheDir=Cache |
infoPanel.softwareTitle=Logiciel |
infoPanel.systemTitle=Informations système |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/MySQLBase.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/PGSQLBase.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/MSSQLBase.java |
---|
Fichier supprimé |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBRoot.java |
---|
150,7 → 150,7 |
@Override |
public Object handle(SQLDataSource ds) throws SQLException { |
// don't create foreign constraints now, so we can insert undefined with cycles |
final List<List<String>> createTablesSQL = ChangeTable.cat(undefinedNonDefaultValues.keySet(), getName(), EnumSet.of(ConcatStep.ADD_FOREIGN)); |
final List<List<String>> createTablesSQL = ChangeTable.cat(undefinedNonDefaultValues.keySet(), getName(), EnumSet.of(ConcatStep.ADD_CONSTRAINT)); |
for (final String sql : createTablesSQL.get(0)) |
ds.execute(sql); |
final Map<SQLCreateTableBase<?>, Number> newUndefIDs; |
312,16 → 312,20 |
this.getBase().fetchTables(TablesMap.createFromTables(this.getSchema().getName(), tableNames)); |
} |
public final SQLCreateRoot getDefinitionSQL(final SQLSystem sys) { |
return this.getDefinitionSQL(sys, true); |
public final SQLCreateRoot getDefinitionSQL() { |
return this.getDefinitionSQL(getDBSystemRoot().getSyntax()); |
} |
public final SQLCreateRoot getDefinitionSQL(final SQLSystem sys, final boolean withTables) { |
final SQLCreateRoot res = new SQLCreateRoot(sys.getSyntax(), this.getName()); |
public final SQLCreateRoot getDefinitionSQL(final SQLSyntax s) { |
return this.getDefinitionSQL(s, true); |
} |
public final SQLCreateRoot getDefinitionSQL(final SQLSyntax s, final boolean withTables) { |
final SQLCreateRoot res = new SQLCreateRoot(s, this.getName()); |
if (withTables) { |
// order by name to be able to do diffs |
for (final SQLTable table : new TreeMap<String, SQLTable>(this.getTablesMap()).values()) { |
res.addTable(table.getCreateTable(sys)); |
res.addTable(table.getCreateTable(s)); |
} |
} |
return res; |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRequestLogModel.java |
---|
30,14 → 30,18 |
@Override |
public Class<?> getColumnClass(int columnIndex) { |
if (columnIndex < 5) |
if (columnIndex == 9) { |
return Integer.class; |
} |
if (columnIndex < 5) { |
return Long.class; |
} |
return String.class; |
} |
@Override |
public int getColumnCount() { |
return 9; |
return 10; |
} |
@Override |
61,6 → 65,8 |
return "Connection"; |
case 8: |
return "Thread"; |
case 9: |
return "Returned rows"; |
} |
return "??"; |
} |
96,6 → 102,8 |
if (l.isInSwing()) |
return "Swing"; |
return l.getThreadId(); |
case 9: |
return l.getResultCount(); |
} |
return ""; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBSystemRoot.java |
---|
76,6 → 76,9 |
private boolean incoherentPath; |
private final PropertyChangeListener coherenceListener; |
@GuardedBy("this") |
private SQLSyntax syntax; |
private final LoadingChangeSupport loadingListenersSupp; |
DBSystemRoot(DBStructureItemJDBC delegate) { |
97,6 → 100,7 |
} |
}; |
this.loadingListenersSupp = new LoadingChangeSupport(this); |
this.syntax = null; |
} |
private synchronized void rootsChanged(PropertyChangeEvent evt) { |
271,7 → 275,7 |
public synchronized final void setUseCache(final boolean useCache) throws SQLException { |
if (this.hasDataSource() && useCache) { |
// null if we shouldn't alter the base |
final SQLCreateMoveableTable createMetadata = SQLSchema.getCreateMetadata(this.getServer().getSQLSystem().getSyntax()); |
final SQLCreateMoveableTable createMetadata = SQLSchema.getCreateMetadata(this.getSyntax()); |
final TablesMap m = new TablesMap(); |
for (final DBRoot r : this.getChildrenMap().values()) { |
// works because when created a root is always fully loaded (we don't allow roots |
390,6 → 394,12 |
return this.ds != null; |
} |
public synchronized final SQLSyntax getSyntax() { |
if (this.syntax == null) |
this.syntax = SQLSyntax.create(this); |
return this.syntax; |
} |
@Override |
protected synchronized void onDrop() { |
this.rmChildrenListener(this.coherenceListener); |
536,7 → 546,7 |
* @see #addRoot(String) |
*/ |
public final DBRoot createRoot(final String rootName) throws SQLException { |
for (final String s : new SQLCreateRoot(SQLSyntax.get(this), rootName).asList(rootName, false, true)) |
for (final String s : new SQLCreateRoot(this.getSyntax(), rootName).asList(rootName, false, true)) |
getDataSource().execute(s); |
return this.addRoot(rootName); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSelect.java |
---|
208,6 → 208,10 |
return getSystemRoot().getServer().getSQLSystem(); |
} |
public final SQLSyntax getSyntax() { |
return getSystemRoot().getSyntax(); |
} |
public String asString() { |
final SQLSystem sys = this.getSQLSystem(); |
231,7 → 235,7 |
archive = Where.and(getUndefWhere(fromTable, alias), archive); |
} |
// archive == null si pas d'archive et pas d'undefined |
if (archive != null && archive.getClause() != "") { |
if (archive != null) { |
result.append("\n WHERE "); |
result.append(archive.getClause()); |
} |
430,19 → 434,22 |
} |
/** |
* Add an ORDER BY {@link SQLTable#getOrderField() t.ORDER}. |
* Add an ORDER BY for the passed table. |
* |
* @param t the table. |
* @param fieldMustExist if <code>true</code> then <code>t</code> must be |
* {@link SQLTable#isOrdered() ordered}. |
* {@link SQLTable#isOrdered() ordered} or have a {@link SQLTable#isRowable() numeric |
* primary key}. |
* @return this. |
* @throws IllegalArgumentException if <code>t</code> isn't ordered and <code>mustExist</code> |
* is <code>true</code>. |
* @throws IllegalArgumentException if <code>t</code> has no usable order field and |
* <code>mustExist</code> is <code>true</code>. |
*/ |
public SQLSelect addOrder(final TableRef t, final boolean fieldMustExist) { |
final SQLField orderField = t.getTable().getOrderField(); |
if (orderField != null) |
this.addFieldOrder(t.getField(orderField.getName())); |
else if (t.getTable().isRowable()) |
this.addFieldOrder(t.getKey()); |
else if (fieldMustExist) |
throw new IllegalArgumentException("table is not ordered : " + t); |
return this; |
977,6 → 984,14 |
return current; |
} |
public final FieldRef followFieldPath(final IFieldPath fp) { |
return this.followFieldPath(fp.getPath().getFirst().getAlias(), fp); |
} |
public final FieldRef followFieldPath(final String tableAlias, final IFieldPath fp) { |
return this.followPath(tableAlias, fp.getPath()).getField(fp.getFieldName()); |
} |
public boolean isExcludeUndefined() { |
return this.generalExcludeUndefined; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxH2.java |
---|
28,6 → 28,7 |
import java.sql.SQLException; |
import java.sql.Timestamp; |
import java.util.ArrayList; |
import java.util.IdentityHashMap; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
36,8 → 37,15 |
class SQLSyntaxH2 extends SQLSyntax { |
static protected final IdentityHashMap<String, String> DATE_SPECS; |
static { |
DATE_SPECS = new IdentityHashMap<String, String>(DateProp.JAVA_DATE_SPECS_PURE); |
DATE_SPECS.put(DateProp.MICROSECOND, "SSS000"); |
} |
SQLSyntaxH2() { |
super(SQLSystem.H2); |
super(SQLSystem.H2, DATE_SPECS); |
this.typeNames.addAll(Boolean.class, "boolean", "bool", "bit"); |
this.typeNames.addAll(Integer.class, "integer", "int", "int4", "mediumint"); |
this.typeNames.addAll(Byte.class, "tinyint"); |
47,7 → 55,8 |
this.typeNames.addAll(Float.class, "real"); |
this.typeNames.addAll(Double.class, "double precision", "float", "float4", "float8"); |
this.typeNames.addAll(Timestamp.class, "timestamp", "smalldatetime", "datetime"); |
this.typeNames.addAll(java.util.Date.class, "date"); |
this.typeNames.addAll(java.sql.Date.class, "date"); |
this.typeNames.addAll(java.sql.Time.class, "time"); |
this.typeNames.addAll(Blob.class, "blob", "tinyblob", "mediumblob", "longblob", "image", |
// byte[] |
"bytea", "raw", "varbinary", "longvarbinary", "binary"); |
167,7 → 176,7 |
@Override |
public void _loadData(final File f, final SQLTable t) { |
checkServerLocalhost(t); |
final String quotedPath = t.getBase().quoteString(f.getAbsolutePath()); |
final String quotedPath = quoteString(f.getAbsolutePath()); |
t.getDBSystemRoot().getDataSource().execute("insert into " + t.getSQLName().quote() + " select * from CSVREAD(" + quotedPath + ", NULL, 'UTF8', ',', '\"', '\\', '\\N') ;"); |
} |
174,8 → 183,8 |
@Override |
protected void _storeData(final SQLTable t, final File f) { |
checkServerLocalhost(t); |
final String quotedPath = t.getBase().quoteString(f.getAbsolutePath()); |
final String quotedSel = t.getBase().quoteString(SQLSyntaxPG.selectAll(t).asString()); |
final String quotedPath = quoteString(f.getAbsolutePath()); |
final String quotedSel = quoteString(SQLSyntaxPG.selectAll(t).asString()); |
t.getBase().getDataSource().execute("CALL CSVWRITE(" + quotedPath + ", " + quotedSel + ", 'UTF8', ',', '\"', '\\', '\\N', '\n');"); |
} |
204,10 → 213,25 |
} |
@Override |
public String getDayOfWeek(String sqlTS) { |
return "DAY_OF_WEEK(" + sqlTS + ")"; |
} |
@Override |
public String getFormatTimestamp(String sqlTS, boolean basic) { |
return "FORMATDATETIME(" + sqlTS + ", " + SQLBase.quoteStringStd(basic ? TS_BASIC_JAVA_FORMAT : TS_EXTENDED_JAVA_FORMAT) + ")"; |
return this.getFormatTimestamp(sqlTS, SQLBase.quoteStringStd(basic ? TS_BASIC_JAVA_FORMAT : TS_EXTENDED_JAVA_FORMAT)); |
} |
@Override |
public final String getFormatTimestamp(String sqlTS, String format) { |
return "FORMATDATETIME(" + sqlTS + ", " + format + ")"; |
} |
@Override |
public String quoteForTimestampFormat(String text) { |
return SQLBase.quoteStringStd(text); |
} |
// (SELECT "C1" as "num", "C2" as "name" FROM VALUES(1, 'Hello'), (2, 'World')) AS V; |
@Override |
public String getConstantTable(List<List<String>> rows, String alias, List<String> columnsAlias) { |
235,28 → 259,28 |
// src can be null since H2 supports alias to Java static functions |
// perhaps join on FUNCTION_COLUMNS to find out parameters' types |
final String src = "coalesce(\"SOURCE\", \"JAVA_CLASS\" || '.' || \"JAVA_METHOD\" ||' parameter(s): ' || \"COLUMN_COUNT\")"; |
return "SELECT ALIAS_SCHEMA as \"schema\", ALIAS_NAME as \"name\", " + src + " as \"src\" FROM \"INFORMATION_SCHEMA\".FUNCTION_ALIASES where ALIAS_CATALOG=" + b.quoteString(b.getMDName()) |
+ " and ALIAS_SCHEMA in (" + quoteStrings(b, schemas) + ")"; |
return "SELECT ALIAS_SCHEMA as \"schema\", ALIAS_NAME as \"name\", " + src + " as \"src\" FROM \"INFORMATION_SCHEMA\".FUNCTION_ALIASES where ALIAS_CATALOG=" + this.quoteString(b.getMDName()) |
+ " and ALIAS_SCHEMA in (" + quoteStrings(schemas) + ")"; |
} |
@Override |
public String getTriggerQuery(SQLBase b, TablesMap tables) { |
return "SELECT \"TRIGGER_NAME\", \"TABLE_SCHEMA\", \"TABLE_NAME\", \"JAVA_CLASS\" as \"ACTION\", \"SQL\" from INFORMATION_SCHEMA.TRIGGERS " + getTablesMapJoin(b, tables) + " where " |
return "SELECT \"TRIGGER_NAME\", \"TABLE_SCHEMA\", \"TABLE_NAME\", \"JAVA_CLASS\" as \"ACTION\", \"SQL\" from INFORMATION_SCHEMA.TRIGGERS " + getTablesMapJoin(tables) + " where " |
+ getInfoSchemaWhere(b); |
} |
private String getTablesMapJoin(final SQLBase b, final TablesMap tables) { |
return getTablesMapJoin(b, tables, SQLBase.quoteIdentifier("TABLE_SCHEMA"), SQLBase.quoteIdentifier("TABLE_NAME")); |
private String getTablesMapJoin(final TablesMap tables) { |
return getTablesMapJoin(tables, SQLBase.quoteIdentifier("TABLE_SCHEMA"), SQLBase.quoteIdentifier("TABLE_NAME")); |
} |
private final String getInfoSchemaWhere(SQLBase b) { |
return "\"TABLE_CATALOG\" = " + b.quoteString(b.getMDName()); |
return "\"TABLE_CATALOG\" = " + this.quoteString(b.getMDName()); |
} |
@Override |
public String getColumnsQuery(SQLBase b, TablesMap tables) { |
return "SELECT \"" + INFO_SCHEMA_NAMES_KEYS.get(0) + "\", \"" + INFO_SCHEMA_NAMES_KEYS.get(1) + "\", \"" + INFO_SCHEMA_NAMES_KEYS.get(2) |
+ "\" , \"CHARACTER_SET_NAME\", \"COLLATION_NAME\", \"SEQUENCE_NAME\" from INFORMATION_SCHEMA.\"COLUMNS\" " + getTablesMapJoin(b, tables) + " where " + getInfoSchemaWhere(b); |
+ "\" , \"CHARACTER_SET_NAME\", \"COLLATION_NAME\", \"SEQUENCE_NAME\" from INFORMATION_SCHEMA.\"COLUMNS\" " + getTablesMapJoin(tables) + " where " + getInfoSchemaWhere(b); |
} |
@Override |
266,7 → 290,7 |
// |
+ "case \"CONSTRAINT_TYPE\" when 'REFERENTIAL' then 'FOREIGN KEY' else \"CONSTRAINT_TYPE\" end as \"CONSTRAINT_TYPE\", \"COLUMN_LIST\", \"CHECK_EXPRESSION\" AS \"DEFINITION\"\n" |
// |
+ "FROM INFORMATION_SCHEMA.CONSTRAINTS " + getTablesMapJoin(b, tables) |
+ "FROM INFORMATION_SCHEMA.CONSTRAINTS " + getTablesMapJoin(tables) |
// where |
+ " where " + getInfoSchemaWhere(b); |
// don't cache since we don't listen on system tables |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLType.java |
---|
18,7 → 18,7 |
import org.openconcerto.utils.CompareUtils; |
import org.openconcerto.utils.StringUtils; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.JDOM2Utils; |
import java.math.BigDecimal; |
import java.math.BigInteger; |
30,16 → 30,14 |
import java.sql.Types; |
import java.util.Arrays; |
import java.util.HashMap; |
import java.util.Iterator; |
import java.util.List; |
import java.util.Map; |
import java.util.Map.Entry; |
import org.jdom2.Element; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.ThreadSafe; |
import org.jdom2.Element; |
/** |
* The type of a SQL field. Allow one to convert a Java object to its SQL serialization. |
* |
50,7 → 48,7 |
@ThreadSafe |
public abstract class SQLType { |
private static Class<?> getClass(int type, final int size) { |
private static Class<?> getClass(int type, final int size, SQLSyntax s) { |
switch (type) { |
case Types.BIT: |
// As of MySQL 5.0.3, BIT is for storing bit-field values |
74,13 → 72,22 |
case Types.TIMESTAMP: |
return Timestamp.class; |
case Types.DATE: |
return java.util.Date.class; |
return java.sql.Date.class; |
case Types.TIME: |
return java.sql.Time.class; |
case Types.INTEGER: |
return Integer.class; |
case Types.SMALLINT: |
/* |
* http://download.oracle.com/otndocs/jcp/jdbc-4_1-mrel-spec/index.html Appendix B : The |
* JDBC 1.0 specification defined the Java object mapping for the SMALLINT and TINYINT |
* JDBC types to be Integer. The Java language did not include the Byte and Short data |
* types when the JDBC 1.0 specification was finalized. The mapping of SMALLINT and |
* TINYINT to Integer is maintained to preserve backwards compatibility |
*/ |
return s.getSystem() == SQLSystem.H2 ? Short.class : Integer.class; |
case Types.TINYINT: |
return Integer.class; |
return s.getSystem() == SQLSystem.H2 ? Byte.class : Integer.class; |
case Types.BINARY: |
case Types.VARBINARY: |
case Types.LONGVARBINARY: |
109,21 → 116,21 |
// useful when no SQLBase is known |
public static SQLType getBoolean(final SQLSyntax s) { |
// TODO use get() once it accepts a SQLSyntax |
final SQLType res = new BooleanType(Types.BOOLEAN, 1, null, Boolean.class); |
res.setSyntax(s); |
return res; |
return getFromSyntax(s, Types.BOOLEAN, 1); |
} |
public static SQLType get(final int type, final int size) { |
return get(null, type, size, null, null); |
public static SQLType getFromSyntax(final SQLSyntax s, final int type, final int size) { |
return get(s, type, size, null, s.getTypeNames(getClass(type, size, s)).iterator().next()); |
} |
public static SQLType get(final SQLBase base, final int type, final int size) { |
return getFromSyntax(SQLSyntax.get(base), type, size); |
} |
/** |
* Get the corresponding type. |
* |
* @param base the base of this type, can be <code>null</code> but {@link #toString(Object)} |
* will have to use standard SQL which might not be valid for all bases (eg escapes). |
* @param base the base of this type, cannot be <code>null</code>. |
* @param type a value from java.sql.Types. |
* @param size the size as COLUMN_SIZE is defined in |
* {@link java.sql.DatabaseMetaData#getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String)} |
133,11 → 140,15 |
* @throws IllegalStateException if type is unknown. |
*/ |
public static SQLType get(final SQLBase base, final int type, final int size, Integer decDigits, final String typeName) { |
final List<String> typeID = Arrays.asList(base == null ? null : base.getURL(), type + "", size + "", String.valueOf(decDigits), typeName); |
return get(SQLSyntax.get(base), type, size, decDigits, typeName); |
} |
public static SQLType get(final SQLSyntax s, final int type, final int size, Integer decDigits, final String typeName) { |
final List<String> typeID = Arrays.asList(s.toString(), type + "", size + "", String.valueOf(decDigits), typeName); |
synchronized (instances) { |
SQLType res = instances.get(typeID); |
if (res == null) { |
final Class<?> clazz = getClass(type, size); |
final Class<?> clazz = getClass(type, size, s); |
if (Boolean.class.isAssignableFrom(clazz)) |
res = new BooleanType(type, size, typeName, clazz); |
else if (Number.class.isAssignableFrom(clazz)) |
154,7 → 165,8 |
else |
// BLOB & CLOB and the rest |
res = new UnknownType(type, size, typeName, clazz); |
res.setBase(base); |
if (s != null) |
res.setSyntax(s); |
instances.put(typeID, res); |
} |
return res; |
170,17 → 182,6 |
return get(base, type, size, decDigits, typeName); |
} |
static void remove(final SQLBase base) { |
synchronized (instances) { |
final Iterator<Entry<List<String>, SQLType>> iter = instances.entrySet().iterator(); |
while (iter.hasNext()) { |
final Entry<List<String>, SQLType> e = iter.next(); |
if (e.getValue().getBase() == base) |
iter.remove(); |
} |
} |
} |
// *** instance |
// a value from java.sql.Types |
195,8 → 196,6 |
private final Class<?> javaType; |
@GuardedBy("this") |
private SQLBase base; |
@GuardedBy("this") |
private SQLSyntax syntax; |
@GuardedBy("this") |
232,6 → 231,11 |
return this.decimalDigits; |
} |
/** |
* The type returned from the DB. |
* |
* @return the java class returned by {@link SQLResultSet#getObject(int)}. |
*/ |
public Class<?> getJavaType() { |
return this.javaType; |
} |
245,34 → 249,19 |
return this.typeName; |
} |
// TODO remove once quoteString() is in SQLSyntax |
private synchronized final void setBase(SQLBase base) { |
// set only once |
assert this.base == null; |
if (base != null) { |
this.base = base; |
this.setSyntax(this.base.getServer().getSQLSystem().getSyntax()); |
} |
} |
private synchronized final void setSyntax(SQLSyntax s) { |
// set only once |
assert this.syntax == null; |
if (s != null) { |
this.syntax = s; |
} |
if (this.syntax != null) |
throw new IllegalStateException("Already set to " + this.syntax); |
this.syntax = s; |
} |
private synchronized final SQLBase getBase() { |
return this.base; |
} |
public synchronized final SQLSyntax getSyntax() { |
return this.syntax; |
} |
protected final String quoteString(String s) { |
return SQLBase.quoteString(this.getBase(), s); |
return SQLSyntax.quoteString(this.getSyntax(), s); |
} |
@Override |
350,7 → 339,7 |
sb.append(this.decimalDigits); |
} |
sb.append("\" typeName=\""); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.typeName)); |
sb.append(JDOM2Utils.OUTPUTTER.escapeAttributeEntities(this.typeName)); |
sb.append("\"/>"); |
this.xml = sb.toString(); |
} |
406,10 → 395,11 |
} |
/** |
* Test whether o is valid for this type. Ie does o is an instance of getJavaType(). |
* Test whether the passed parameter is valid for this type. |
* |
* @param o the object to test. |
* @return <code>true</code> if o can be passed to {@link #toString(Object)}. |
* @return <code>true</code> if o can be passed to {@link #toString(Object)}, always |
* <code>true</code> for an instance of {@link #getJavaType()}. |
* @see #check(Object) |
*/ |
public boolean isValid(Object o) { |
503,7 → 493,7 |
@Override |
public final String toStringRaw(Object o) { |
// time has no special characters to escape |
return "'" + toCSVRaw(o) + "'"; |
return getSyntax().cast("'" + toCSVRaw(o) + "'", this); |
} |
static protected long getTime(Object o) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesListFetcher.java |
---|
28,6 → 28,7 |
import org.openconcerto.utils.RecursionType; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.ITransformer; |
import org.openconcerto.utils.cc.Transformer; |
import java.sql.ResultSet; |
import java.sql.SQLException; |
788,18 → 789,25 |
} |
public final SQLSelect getReq() { |
return this.getReq(null); |
return this.getReq(null, null); |
} |
// see fetch() comment as to why the Where parameter isn't public. |
private synchronized final SQLSelect getReq(final Where w) { |
static private final SQLSelect checkTr(final List<String> origSelect, final SQLSelect tr) { |
if (!origSelect.equals(tr.getSelect())) |
throw new IllegalArgumentException("Select clause cannot be modified"); |
return tr; |
} |
public synchronized final SQLSelect getReq(final Where w, final ITransformer<SQLSelect, SQLSelect> selTransf) { |
checkTable(w); |
final boolean isNopTransf = selTransf == null || selTransf == Transformer.<SQLSelect> nopTransformer(); |
if (this.isFrozen()) { |
if (w == null) { |
if (w == null && isNopTransf) { |
return this.frozen; |
} else { |
final SQLSelect res = new SQLSelect(this.frozen); |
res.andWhere(w); |
return res; |
final SQLSelect copy = new SQLSelect(this.frozen); |
final SQLSelect res = isNopTransf ? copy : checkTr(copy.getSelect(), selTransf.transformChecked(copy)); |
return res.andWhere(w); |
} |
} |
841,11 → 849,14 |
if (this.getSelID() != null) |
sel.andWhere(getIDWhere(t, this.getSelID())); |
final List<String> origSel = new ArrayList<String>(sel.getSelect()); |
SQLSelect res = sel; |
for (final ITransformer<SQLSelect, SQLSelect> tr : this.getSelectTransformers()) { |
res = tr.transformChecked(res); |
} |
return res.andWhere(w); |
if (!isNopTransf) |
res = selTransf.transformChecked(res); |
return checkTr(origSel, res).andWhere(w); |
} |
static private Where getIDWhere(final SQLTable t, final Number id) { |
1147,17 → 1158,20 |
* table. |
*/ |
public final List<SQLRowValues> fetch(final Where w, final Boolean unmodifiableRows) throws IllegalArgumentException { |
return this.fetch(true, w, unmodifiableRows); |
return this.fetch(w, null, unmodifiableRows); |
} |
private final List<SQLRowValues> fetch(final boolean merge, final Where w, final Boolean unmodifiableRows) throws IllegalArgumentException { |
checkTable(w); |
public final List<SQLRowValues> fetch(final Where w, final ITransformer<SQLSelect, SQLSelect> selTransf, final Boolean unmodifiableRows) throws IllegalArgumentException { |
return this.fetch(true, w, selTransf, unmodifiableRows); |
} |
private final List<SQLRowValues> fetch(final boolean merge, final Where w, final ITransformer<SQLSelect, SQLSelect> selTransf, final Boolean unmodifiableRows) throws IllegalArgumentException { |
final SQLSelect req; |
final Map<Path, Map<Path, SQLRowValuesListFetcher>> grafts; |
final boolean freezeRows; |
// the only other internal state used is this.descendantPath which is final immutable |
synchronized (this) { |
req = this.getReq(w); |
req = this.getReq(w, selTransf); |
grafts = this.getGrafts(); |
freezeRows = unmodifiableRows == null ? this.areReturnedRowsUnmodifiable() : unmodifiableRows.booleanValue(); |
} |
1164,9 → 1178,7 |
// getName() would take 5% of ResultSetHandler.handle() |
final List<FieldRef> selectFields = req.getSelectFields(); |
final int selectFieldsSize = selectFields.size(); |
final List<String> selectFieldsNames = new ArrayList<String>(selectFieldsSize); |
for (final FieldRef f : selectFields) |
selectFieldsNames.add(f.getField().getName()); |
final List<String> selectFieldsNames = req.getSelectNames(); |
final SQLTable table = getGraph().getTable(); |
// create a flat list of the graph nodes, we just need the table, field count and the index |
1198,8 → 1210,8 |
// otherwise walk() would already have thrown an exception |
assert fieldIndex.get() <= selectFieldsSize; |
if (fieldIndex.get() != selectFieldsSize) { |
throw new IllegalStateException( |
"Fields have been added to the select (which is useless, since only fields specified by rows are returned) : " + selectFields.subList(fieldIndex.get(), selectFieldsSize)); |
throw new IllegalStateException("Items have been added to the select (which is useless, since only fields specified by rows are returned and WHERE cannot access SELECT columns) : " |
+ selectFields.subList(fieldIndex.get(), selectFieldsSize)); |
} |
assert l.size() == graphSize : "All nodes weren't explored once : " + l.size() + " != " + graphSize + "\n" + this.getGraph().printGraph(); |
1245,7 → 1257,7 |
final SQLRowValuesListFetcher graft = e.getValue(); |
// don't merge then... |
final List<SQLRowValues> referentVals = graft.fetch(false, new Where(graft.getGraph().getTable().getKey(), ids), false); |
final List<SQLRowValues> referentVals = graft.fetch(false, new Where(graft.getGraph().getTable().getKey(), ids), null, false); |
// ...but now |
merge(merged, referentVals, byRows, descendantPath); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxMS.java |
---|
27,7 → 27,6 |
import org.openconcerto.utils.RTInterruptedException; |
import org.openconcerto.utils.StringUtils; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.IClosure; |
import org.openconcerto.utils.cc.ITransformer; |
import java.io.BufferedReader; |
47,6 → 46,7 |
import java.sql.Types; |
import java.util.Arrays; |
import java.util.BitSet; |
import java.util.IdentityHashMap; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
54,8 → 54,23 |
class SQLSyntaxMS extends SQLSyntax { |
static private final IdentityHashMap<String, String> DATE_SPECS; |
static { |
DATE_SPECS = new IdentityHashMap<String, String>(); |
DATE_SPECS.put(DateProp.YEAR, "yyyy"); |
DATE_SPECS.put(DateProp.MONTH_NAME, "MMMM"); |
DATE_SPECS.put(DateProp.MONTH_NUMBER, "MM"); |
DATE_SPECS.put(DateProp.DAY_IN_MONTH, "dd"); |
DATE_SPECS.put(DateProp.DAY_NAME_IN_WEEK, "dddd"); |
DATE_SPECS.put(DateProp.HOUR, "HH"); |
DATE_SPECS.put(DateProp.MINUTE, "mm"); |
DATE_SPECS.put(DateProp.SECOND, "ss"); |
DATE_SPECS.put(DateProp.MICROSECOND, "ffffff"); |
} |
SQLSyntaxMS() { |
super(SQLSystem.MSSQL); |
super(SQLSystem.MSSQL, DATE_SPECS); |
this.typeNames.addAll(Boolean.class, "bit"); |
// tinyint is unsigned |
this.typeNames.addAll(Short.class, "smallint", "tinyint"); |
63,12 → 78,12 |
this.typeNames.addAll(Long.class, "bigint"); |
this.typeNames.addAll(BigDecimal.class, "decimal", "numeric", "smallmoney", "money"); |
this.typeNames.addAll(Float.class, "real"); |
this.typeNames.addAll(Double.class, "float"); |
this.typeNames.addAll(Timestamp.class, "smalldatetime", "datetime"); |
this.typeNames.addAll(Double.class, "double precision", "float"); |
this.typeNames.addAll(Timestamp.class, "datetime2", "datetime", "smalldatetime"); |
this.typeNames.addAll(java.sql.Date.class, "date"); |
this.typeNames.addAll(java.sql.Time.class, "time"); |
this.typeNames.addAll(Blob.class, "image", |
// byte[] |
// byte[] |
"varbinary", "binary"); |
this.typeNames.addAll(Clob.class, "text", "ntext", "unitext"); |
this.typeNames.addAll(String.class, "char", "varchar", "nchar", "nvarchar", "unichar", "univarchar"); |
75,6 → 90,22 |
} |
@Override |
public final String quoteString(String s) { |
final String res = super.quoteString(s); |
if (s == null) |
return res; |
// only use escape form if needed (=> equals with other systems most of the time) |
boolean simpleASCII = true; |
final int l = s.length(); |
for (int i = 0; simpleASCII && i < l; i++) { |
final char c = s.charAt(i); |
simpleASCII = c <= 0xFF; |
} |
// see http://msdn.microsoft.com/fr-fr/library/ms191200(v=sql.105).aspx |
return simpleASCII ? res : "N" + res; |
} |
@Override |
public int getMaximumIdentifierLength() { |
// https://msdn.microsoft.com/en-us/library/ms143432.aspx |
return 128; |
81,11 → 112,6 |
} |
@Override |
SQLBase createBase(SQLServer server, String name, final IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit) { |
return new MSSQLBase(server, name, systemRootInit, login, pass, dsInit); |
} |
@Override |
public String getInitSystemRoot() { |
final String sql; |
try { |
108,16 → 134,6 |
} |
@Override |
public String getDateAndTimeType() { |
return "datetime2"; |
} |
@Override |
public String getBooleanType() { |
return "bit"; |
} |
@Override |
public int getMaximumVarCharLength() { |
// http://msdn.microsoft.com/en-us/library/ms176089(v=sql.105).aspx |
return 8000; |
165,7 → 181,7 |
final String s = enable ? "with check check constraint all" : "nocheck constraint all"; |
return "exec sp_MSforeachtable @command1 = 'ALTER TABLE ? " + s + "' , @whereand = " + |
// |
b.getBase().quoteString("and schema_id = SCHEMA_ID( " + b.getBase().quoteString(b.getName()) + " )"); |
quoteString("and schema_id = SCHEMA_ID( " + quoteString(b.getName()) + " )"); |
} |
@Override |
193,7 → 209,7 |
// |
" join [test].[sys].[columns] cols on t.object_id = cols.object_id and cols.column_id = indexCols.column_id \n" + |
// |
" where schema_name(t.schema_id) = " + t.getBase().quoteString(t.getSchema().getName()) + " and t.name = " + t.getBase().quoteString(t.getName()) + "\n" |
" where schema_name(t.schema_id) = " + quoteString(t.getSchema().getName()) + " and t.name = " + quoteString(t.getName()) + "\n" |
// |
+ "ORDER BY \"NON_UNIQUE\", \"TYPE\", \"INDEX_NAME\", \"ORDINAL_POSITION\";"; |
// don't cache since we don't listen on system tables |
218,7 → 234,7 |
public boolean isUniqueException(SQLException exn) { |
return SQLUtils.findWithSQLState(exn).getErrorCode() == 2601; |
} |
@Override |
public boolean isDeadLockException(SQLException exn) { |
return SQLUtils.findWithSQLState(exn).getErrorCode() == 1205; |
490,10 → 506,10 |
@Override |
public String getFunctionQuery(SQLBase b, Set<String> schemas) { |
return " select name, schema_name(schema_id) as \"schema\", cast(OBJECT_DEFINITION(object_id) as varchar(4096)) as \"src\"\n" |
// |
// |
+ " FROM " + new SQLName(b.getName(), "sys", "objects") + "\n" |
// scalar, inline table-valued, table-valued |
+ " where type IN ('FN', 'IF', 'TF') and SCHEMA_NAME( schema_id ) in (" + quoteStrings(b, schemas) + ") "; |
+ " where type IN ('FN', 'IF', 'TF') and SCHEMA_NAME( schema_id ) in (" + quoteStrings(schemas) + ") "; |
} |
@Override |
505,7 → 521,7 |
// |
+ "join " + new SQLName(b.getName(), "sys", "objects") + " tabl on trig.parent_id = tabl.object_id\n" |
// requested tables |
+ getTablesMapJoin(b, tables, "SCHEMA_NAME( tabl.schema_id )", "tabl.name"); |
+ getTablesMapJoin(tables, "SCHEMA_NAME( tabl.schema_id )", "tabl.name"); |
} |
@Override |
518,20 → 534,18 |
return "SELECT TABLE_SCHEMA as \"" + INFO_SCHEMA_NAMES_KEYS.get(0) + "\", TABLE_NAME as \"" + INFO_SCHEMA_NAMES_KEYS.get(1) + "\", COLUMN_NAME as \"" + INFO_SCHEMA_NAMES_KEYS.get(2) |
+ "\" , CHARACTER_SET_NAME as \"CHARACTER_SET_NAME\", COLLATION_NAME as \"COLLATION_NAME\" from INFORMATION_SCHEMA.COLUMNS\n" + |
// requested tables |
getTablesMapJoin(b, tables, "TABLE_SCHEMA", "TABLE_NAME"); |
getTablesMapJoin(tables, "TABLE_SCHEMA", "TABLE_NAME"); |
} |
@Override |
public List<Map<String, Object>> getConstraints(SQLBase b, TablesMap tables) throws SQLException { |
final String where = getTablesMapJoin(b, tables, "SCHEMA_NAME(t.schema_id)", "t.name"); |
final String where = getTablesMapJoin(tables, "SCHEMA_NAME(t.schema_id)", "t.name"); |
final String sel = "SELECT SCHEMA_NAME(t.schema_id) AS \"TABLE_SCHEMA\", t.name AS \"TABLE_NAME\", k.name AS \"CONSTRAINT_NAME\", case k.type when 'UQ' then 'UNIQUE' when 'PK' then 'PRIMARY KEY' end as \"CONSTRAINT_TYPE\", col_name(c.object_id, c.column_id) AS \"COLUMN_NAME\", c.key_ordinal AS \"ORDINAL_POSITION\", null AS [DEFINITION]\n" |
+ "FROM sys.key_constraints k\n" |
// |
+ "JOIN sys.index_columns c ON c.object_id = k.parent_object_id AND c.index_id = k.unique_index_id\n" |
// |
+ "JOIN sys.tables t ON t.object_id = k.parent_object_id\n" |
+ where |
+ "\nUNION ALL\n" |
+ "JOIN sys.tables t ON t.object_id = k.parent_object_id\n" + where + "\nUNION ALL\n" |
// |
+ "SELECT SCHEMA_NAME(t.schema_id) AS \"TABLE_SCHEMA\", t.name AS \"TABLE_NAME\", k.name AS \"CONSTRAINT_NAME\", 'CHECK' as \"CONSTRAINT_TYPE\", col.name AS \"COLUMN_NAME\", 1 AS \"ORDINAL_POSITION\", k.[definition] AS [DEFINITION]\n" |
+ "FROM sys.check_constraints k\n" |
540,8 → 554,7 |
// |
+ "left join sys.columns col on k.parent_column_id = col.column_id and col.object_id = t.object_id\n" |
// |
+ where |
+ "\nUNION ALL\n" |
+ where + "\nUNION ALL\n" |
// |
+ "SELECT SCHEMA_NAME(t.schema_id) AS [TABLE_SCHEMA], t.name AS [TABLE_NAME], k.name AS [CONSTRAINT_NAME], 'DEFAULT' as [CONSTRAINT_TYPE], col.name AS [COLUMN_NAME], 1 AS [ORDINAL_POSITION], k.[definition] AS [DEFINITION]\n" |
+ "FROM sys.[default_constraints] k\n" |
576,8 → 589,18 |
} |
@Override |
public String getDayOfWeek(String sqlTS) { |
return "SELECT DATEPART(dw, " + sqlTS + ")"; |
} |
@Override |
public String getMonth(String sqlTS) { |
return "SELECT DATEPART(month, " + sqlTS + ")"; |
} |
@Override |
public String getFormatTimestamp(String sqlTS, boolean basic) { |
final String extended = "CONVERT(nvarchar(30), CAST(" + sqlTS + " as datetime), 126) + '000'"; |
final String extended = "CONVERT(nvarchar(30), " + sqlTS + ", 126) + '000'"; |
if (basic) { |
return "replace( replace( " + extended + ", '-', ''), ':' , '' )"; |
} else { |
584,4 → 607,14 |
return extended; |
} |
} |
@Override |
public String getFormatTimestamp(String sqlTS, String nativeFormat) { |
return "FORMAT(" + sqlTS + ", " + nativeFormat + ")"; |
} |
@Override |
public String quoteForTimestampFormat(String text) { |
return StringUtils.doubleQuote(text); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java |
---|
13,8 → 13,11 |
package org.openconcerto.sql.model; |
import static org.openconcerto.xml.JDOM2Utils.OUTPUTTER; |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.SQLSelect.ArchiveMode; |
import org.openconcerto.sql.model.SQLSelect.LockStrength; |
import org.openconcerto.sql.model.SQLSyntax.ConstraintType; |
import org.openconcerto.sql.model.SQLTableEvent.Mode; |
import org.openconcerto.sql.model.graph.DatabaseGraph; |
38,7 → 41,6 |
import org.openconcerto.utils.cc.CopyOnWriteMap; |
import org.openconcerto.utils.cc.CustomEquals; |
import org.openconcerto.utils.change.CollectionChangeEventCreator; |
import org.openconcerto.xml.JDOMUtils; |
import java.math.BigDecimal; |
import java.sql.DatabaseMetaData; |
214,7 → 216,7 |
l.add(Arrays.asList(b.quoteString(tableName), undefSQL)); |
} |
} |
final SQLSyntax syntax = system.getSyntax(); |
final SQLSyntax syntax = schema.getDBSystemRoot().getSyntax(); |
if (toInsert.size() > 0) { |
// INSERT |
SQLRowValues.insertCount(undefT, "(" + SQLSyntax.quoteIdentifiers(Arrays.asList(UNDEF_TABLE_TABLENAME_FIELD, UNDEF_TABLE_ID_FIELD)) + ") " + syntax.getValues(toInsert, 2)); |
310,7 → 312,7 |
private String version; |
private final CopyOnWriteMap<String, SQLField> fields; |
@GuardedBy("this") |
private final Set<SQLField> primaryKeys; |
private Set<SQLField> primaryKeys; |
// the vast majority of our code use getKey(), so cache it for performance |
@GuardedBy("this") |
private SQLField primaryKey; |
363,8 → 365,7 |
} |
}; |
assert isOrdered(this.fields); |
// order matters (eg for indexes) |
this.primaryKeys = new LinkedHashSet<SQLField>(); |
this.primaryKeys = Collections.emptySet(); |
this.primaryKey = null; |
this.primaryKeyOK = true; |
this.keys = null; |
512,7 → 513,7 |
// must be called in setState() after fields have been set (for isRowable()) |
private int fetchUndefID() { |
final int res; |
int res; |
final SQLField pk; |
synchronized (this) { |
pk = isRowable() ? this.getKey() : null; |
520,8 → 521,14 |
if (pk != null) { |
final Tuple2<Boolean, Number> currentValue = getUndefID(this.getSchema(), this.getName()); |
if (!currentValue.get0()) { |
// no row |
res = this.findMinID(pk); |
try { |
// no row |
res = this.findMinID(pk); |
} catch (Exception e) { |
// we ***** don't care |
e.printStackTrace(); |
res = SQLRow.NONEXISTANT_ID; |
} |
} else { |
// a row |
final Number id = currentValue.get1(); |
546,8 → 553,9 |
// empty table |
throw new IllegalStateException(this + " is empty, can not infer UNDEFINED_ID"); |
} else { |
final String update = SQLSyntax.get(this).getInsertOne(new SQLName(this.getDBRoot().getName(), undefTable), Arrays.asList(UNDEF_TABLE_TABLENAME_FIELD, UNDEF_TABLE_ID_FIELD), |
getBase().quoteString(this.getName()), String.valueOf(undef)); |
final SQLSyntax syntax = SQLSyntax.get(this); |
final String update = syntax.getInsertOne(new SQLName(this.getDBRoot().getName(), undefTable), Arrays.asList(UNDEF_TABLE_TABLENAME_FIELD, UNDEF_TABLE_ID_FIELD), |
syntax.quoteString(this.getName()), String.valueOf(undef)); |
Log.get().config("the first row (which should be the undefined):\n" + update); |
return undef.intValue(); |
} |
630,9 → 638,11 |
} |
} |
this.primaryKeys.clear(); |
// order matters (e.g. for indexes) |
final Set<SQLField> newPK = new LinkedHashSet<SQLField>(); |
for (final String pk : primaryKeys) |
this.primaryKeys.add(this.getField(pk)); |
newPK.add(this.getField(pk)); |
this.primaryKeys = Collections.unmodifiableSet(newPK); |
this.primaryKey = primaryKeys.size() == 1 ? this.getField(primaryKeys.get(0)) : null; |
this.primaryKeyOK = primaryKeys.size() <= 1; |
762,7 → 772,7 |
* @return the fields (SQLField) which are the keys of this table, can be empty. |
*/ |
public synchronized Set<SQLField> getPrimaryKeys() { |
return Collections.unmodifiableSet(this.primaryKeys); |
return this.primaryKeys; |
} |
public final Set<Link> getForeignLinks() { |
1117,7 → 1127,7 |
} |
} |
} |
return res; |
return Collections.unmodifiableSet(res); |
} |
public final Set<String> getFieldsNames(final VirtualFields vfs) { |
1128,6 → 1138,23 |
return res; |
} |
public final List<SQLField> getFields(final Collection<String> names) { |
return this.getFields(names, new ArrayList<SQLField>()); |
} |
public final <T extends Collection<SQLField>> T getFields(final Collection<String> names, final T res) { |
return this.getFields(names, res, true); |
} |
public final <T extends Collection<SQLField>> T getFields(final Collection<String> names, final T res, final boolean required) { |
for (final String name : names) { |
final SQLField f = required ? this.getField(name) : this.getFieldRaw(name); |
if (f != null) |
res.add(f); |
} |
return res; |
} |
/** |
* Retourne les champs du contenu de cette table. C'est à dire ni la clef primaire, ni les |
* champs d'archive et d'ordre. |
1267,7 → 1294,7 |
* archivée. |
*/ |
public SQLRow checkValidity(int ID) { |
SQLRow row = this.getUncheckedRow(ID); |
final SQLRow row = SQLRow.createFromSelect(this, VirtualFields.PRIMARY_KEY.union(VirtualFields.ARCHIVE), ID, LockStrength.SHARE); |
// l'inverse de getValidRow() |
return row.isValid() ? null : row; |
} |
1684,13 → 1711,13 |
public synchronized String toXML() { |
final StringBuilder sb = new StringBuilder(16000); |
sb.append("<table name=\""); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(this.getName())); |
sb.append(OUTPUTTER.escapeAttributeEntities(this.getName())); |
sb.append("\""); |
final String schemaName = this.getSchema().getName(); |
if (schemaName != null) { |
sb.append(" schema=\""); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(schemaName)); |
sb.append(OUTPUTTER.escapeAttributeEntities(schemaName)); |
sb.append('"'); |
} |
1698,7 → 1725,7 |
if (getType() != null) { |
sb.append(" type=\""); |
sb.append(JDOMUtils.OUTPUTTER.escapeAttributeEntities(getType())); |
sb.append(OUTPUTTER.escapeAttributeEntities(getType())); |
sb.append('"'); |
} |
1706,7 → 1733,7 |
if (this.getComment() != null) { |
sb.append("<comment>"); |
sb.append(JDOMUtils.OUTPUTTER.escapeElementEntities(this.getComment())); |
sb.append(OUTPUTTER.escapeElementEntities(this.getComment())); |
sb.append("</comment>\n"); |
} |
for (SQLField field : this.fields.values()) { |
1924,11 → 1951,11 |
} |
public final SQLCreateMoveableTable getCreateTable() { |
return this.getCreateTable(this.getServer().getSQLSystem()); |
return this.getCreateTable(SQLSyntax.get(this)); |
} |
public synchronized final SQLCreateMoveableTable getCreateTable(final SQLSystem system) { |
final SQLSyntax syntax = SQLSyntax.get(system); |
public synchronized final SQLCreateMoveableTable getCreateTable(final SQLSyntax syntax) { |
final SQLSystem system = syntax.getSystem(); |
final SQLCreateMoveableTable res = new SQLCreateMoveableTable(syntax, this.getDBRoot().getName(), this.getName()); |
for (final SQLField f : this.getOrderedFields()) { |
res.addColumn(f); |
1954,7 → 1981,6 |
// not null" in addUniqueConstraint(). Thus when converting to another system we must |
// parse indexes to recreate actual constraints. |
final boolean convertMSIndex = this.getServer().getSQLSystem() == SQLSystem.MSSQL && system != SQLSystem.MSSQL; |
final Set<List<SQLField>> foreignKeysFields = getForeignKeysFields(); |
for (final Index i : this.getIndexes(true)) { |
Value<String> msWhere = null; |
if (convertMSIndex && (msWhere = i.getMSUniqueWhere()).hasValue()) { |
1961,12 → 1987,12 |
if (msWhere.getValue() != null) |
Log.get().warning("MS filter might not be valid in " + system + " : " + msWhere.getValue()); |
res.addUniqueConstraint(i.getName(), i.getCols(), msWhere.getValue()); |
} else if (!system.autoCreatesFKIndex() || !foreignKeysFields.contains(i.getFields())) { |
} else { |
// partial unique index sometimes cannot be handled natively by the DB system |
if (i.isUnique() && i.getFilter() != null && !system.isIndexFilterConditionSupported()) |
res.addUniqueConstraint(i.getName(), i.getCols(), i.getFilter()); |
else |
res.addOutsideClause(syntax.getCreateIndex(i)); |
res.addIndex(i); |
} |
} |
} catch (SQLException e) { |
2040,13 → 2066,13 |
* automatically. |
* |
* @return the list of indexes. |
* @throws SQLException if an error occurs. |
* @throws SQLException if an error occurs while accessing the DB. |
*/ |
public synchronized final List<Index> getIndexes() throws SQLException { |
public final List<Index> getIndexes() throws SQLException { |
return this.getIndexes(false); |
} |
protected synchronized final List<Index> getIndexes(final boolean normalized) throws SQLException { |
public synchronized final List<Index> getIndexes(final boolean normalized) throws SQLException { |
// in pg, a unique constraint creates a unique index that is not removeable |
// (except of course if we drop the constraint) |
// in mysql unique constraints and indexes are one and the same thing |
2065,7 → 2091,7 |
final List<Index> indexes = new ArrayList<Index>(); |
Index currentIndex = null; |
for (final Map<String, Object> norm : this.getServer().getSQLSystem().getSyntax().getIndexInfo(this)) { |
for (final Map<String, Object> norm : this.getDBSystemRoot().getSyntax().getIndexInfo(this)) { |
final Index index = new Index(norm); |
final short seq = ((Number) norm.get("ORDINAL_POSITION")).shortValue(); |
if (seq == 1) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBFileCache.java |
---|
15,6 → 15,7 |
import org.openconcerto.sql.Configuration; |
import org.openconcerto.sql.model.graph.DatabaseGraph; |
import org.openconcerto.utils.BaseDirs; |
import org.openconcerto.utils.FileUtils; |
import org.openconcerto.utils.ProductInfo; |
import org.openconcerto.utils.StringUtils; |
50,18 → 51,18 |
private static final String FILE_STRUCT_VERSION = "20080904-1411"; |
static private final File getFwkSaveDir() { |
final File confDir; |
final BaseDirs confDir; |
// require at least an application name, since settings might influence what is to be saved |
// MAYBE pass the server and allow it to have an ID |
// (this would handle the case when one app needs two different connections to a server) |
if (Configuration.getInstance() != null) { |
confDir = Configuration.getInstance().getConfDir(); |
confDir = Configuration.getInstance().getBaseDirs(); |
} else if (ProductInfo.getInstance() != null) { |
confDir = new File(Configuration.getDefaultConfDir(), ProductInfo.getInstance().getName()); |
confDir = BaseDirs.create(ProductInfo.getInstance()); |
} else { |
return null; |
} |
return new File(confDir, "DBCache/" + FILE_STRUCT_VERSION); |
return new File(confDir.getCacheFolder(), "DBCache/" + FILE_STRUCT_VERSION); |
} |
static private final File getValidFwkSaveDir() { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/StructureSource.java |
---|
169,7 → 169,7 |
// DatabaseMetaData param to avoid re-asking it |
protected final Set<String> getJDBCSchemas(final DatabaseMetaData metaData) throws SQLException { |
// getSchemas(this.getBase().getMDName(), null) not implemented by pg |
final Set<String> res = new HashSet<String>((List) SQLDataSource.COLUMN_LIST_HANDLER.handle(metaData.getSchemas())); |
final Set<String> res = new HashSet<String>(ColumnListHandlerGeneric.create(String.class).handle(metaData.getSchemas())); |
// if db does not support schemas |
if (res.isEmpty() && !this.getBase().getServer().getSQLSystem().getLevels().contains(HierarchyLevel.SQLSCHEMA)) |
res.add(null); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBStructureItem.java |
---|
112,7 → 112,7 |
} |
public final boolean contains(String childName) { |
return this.getChildrenNames().contains(childName); |
return this.getChildrenMap().containsKey(childName); |
} |
/** |
176,14 → 176,20 |
} |
private final D getAncestor(int level) { |
if (level < 0) |
if (level < 0) { |
throw new IllegalArgumentException("negative level: " + level); |
else if (level == 0) |
} else if (level == 0) { |
return thisAsD(); |
else if (this.getParent() == null) |
throw new IllegalArgumentException(this + " is the root, can't go up of " + level); |
else |
return this.getParent().getAncestor(level - 1); |
} else { |
// need to upcast parent since D extends this class and private methods aren't inherited |
// http://stackoverflow.com/questions/7719843/type-parameterized-field-of-a-generic-class-becomes-invisible-after-upgrading-to |
// http://stackoverflow.com/questions/15062841/java-casting-with-method-calls |
final DBStructureItem<D> parentForJavac = this.getParent(); |
if (parentForJavac == null) |
throw new IllegalArgumentException(this + " is the root, can't go up of " + level); |
else |
return parentForJavac.getAncestor(level - 1); |
} |
} |
/** |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java |
---|
18,6 → 18,7 |
import org.openconcerto.sql.Log; |
import org.openconcerto.sql.model.SQLSelect.ArchiveMode; |
import org.openconcerto.sql.model.SQLSelect.LockStrength; |
import org.openconcerto.sql.model.SQLTable.VirtualFields; |
import org.openconcerto.sql.model.graph.Link; |
import org.openconcerto.sql.model.graph.Link.Direction; |
186,6 → 187,25 |
return res; |
} |
static final SQLRow createFromSelect(final SQLTable t, final VirtualFields vfs, final int id, final LockStrength l) { |
final SQLSelect sel = new SQLSelect(true).addAllSelect(t.getFields(vfs)); |
sel.setLockStrength(l); |
sel.setWhere(new Where(t.getKey(), "=", id)); |
return new SQLRow(t, id, t.getDBSystemRoot().getDataSource().execute1(sel.asString())); |
} |
/** |
* Create an empty existing row (without checking the DB). |
* |
* @param t the table. |
* @param id the ID. |
* @return a new {@link #exists() existing} {@link #isFilled() filled} {@link #getFields() |
* empty} row. |
*/ |
static final SQLRow createEmpty(final SQLTable t, final int id) { |
return new SQLRow(t, id, Collections.<String, Object> emptyMap()); |
} |
private final int ID; |
private final Number idNumber; |
private Map<String, Object> values; |
226,7 → 246,7 |
private SQLRow(SQLTable table, final Number id, Map<String, ?> values) { |
this(table, id == null ? getID(values, table, false) : id); |
// faire une copie, sinon backdoor pour changer les valeurs sans qu'on s'en aperçoive |
this.setValues(new HashMap<String, Object>(values)); |
this.setValues(values == null ? null : new HashMap<String, Object>(values)); |
} |
// return ID, must always be present but may be null if <code>nullAllowed</code> |
428,18 → 448,6 |
return this.getForeignRow(fieldName); |
} |
@Override |
public Number getForeignIDNumber(String fieldName) throws IllegalArgumentException { |
final SQLRow foreignRow = this.getForeignRow(fieldName, SQLRowMode.NO_CHECK); |
return foreignRow == null ? null : foreignRow.getIDNumber(); |
} |
@Override |
public boolean isForeignEmpty(String fieldName) { |
final SQLRow foreignRow = this.getForeignRow(fieldName, SQLRowMode.NO_CHECK); |
return foreignRow == null || foreignRow.isUndefined(); |
} |
/** |
* Retourne la ligne sur laquelle pointe le champ passé. Elle peut être archivé ou indéfinie. |
* |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLBase.java |
---|
52,11 → 52,11 |
import java.util.regex.Matcher; |
import java.util.regex.Pattern; |
import org.apache.commons.dbutils.ResultSetHandler; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.ThreadSafe; |
import org.apache.commons.dbutils.ResultSetHandler; |
/** |
* Une base de donnée SQL. Une base est unique, pour obtenir une instance il faut passer par |
* SQLServer. Une base permet d'accéder aux tables qui la composent, ainsi qu'à son graphe. |
67,7 → 67,7 |
* @see #getGraph() |
*/ |
@ThreadSafe |
public class SQLBase extends SQLIdentifier { |
public final class SQLBase extends SQLIdentifier { |
/** |
* Boolean system property, if <code>true</code> then the structure and the graph of SQL base |
154,7 → 154,6 |
protected synchronized void onDrop() { |
// allow schemas (and their descendants) to be gc'd even we aren't |
this.schemas.clear(); |
SQLType.remove(this); |
super.onDrop(); |
} |
782,6 → 781,7 |
static private final Pattern percent = Pattern.compile("%."); |
private final static String quote(final SQLBase b, final String pattern, Object... params) { |
final SQLSyntax s = b == null ? null : SQLSyntax.get(b); |
final Matcher m = percent.matcher(pattern); |
final StringBuffer sb = new StringBuffer(); |
int i = 0; |
794,7 → 794,7 |
} else { |
final Object param = params[i++]; |
if (modifier == 's') { |
replacement = quoteString(b, param.toString()); |
replacement = SQLSyntax.quoteString(s, param.toString()); |
} else if (modifier == 'i') { |
if (param instanceof SQLName) |
replacement = ((SQLName) param).quote(); |
832,11 → 832,11 |
* @see #quoteStringStd(String) |
*/ |
public String quoteString(String s) { |
return quoteStringStd(s); |
return SQLSyntax.get(this).quoteString(s); |
} |
static private final Pattern singleQuote = Pattern.compile("'", Pattern.LITERAL); |
static private final Pattern quotedPatrn = Pattern.compile("^'(('')|[^'])*'$"); |
static public final Pattern quotedPatrn = Pattern.compile("'(('')|[^'])*'"); |
static private final Pattern twoSingleQuote = Pattern.compile("''", Pattern.LITERAL); |
/** |
864,15 → 864,11 |
* @see #quoteStringStd(String) |
*/ |
public final static String unquoteStringStd(String s) { |
if (!quotedPatrn.matcher(s).find()) |
if (!quotedPatrn.matcher(s).matches()) |
throw new IllegalArgumentException("Invalid quoted string " + s); |
return twoSingleQuote.matcher(s.substring(1, s.length() - 1)).replaceAll("'"); |
} |
public final static String quoteString(SQLBase b, String s) { |
return b == null ? quoteStringStd(s) : b.quoteString(s); |
} |
// * quoteIdentifier |
static private final Pattern doubleQuote = Pattern.compile("\""); |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSearchMode.java |
---|
13,35 → 13,66 |
package org.openconcerto.sql.model; |
import java.util.Arrays; |
import java.util.Collections; |
import java.util.List; |
public abstract class SQLSearchMode { |
static public final SQLSearchMode EQUALS = new SQLSearchMode() { |
@Override |
public String generateSQL(final DBRoot r, final String term) { |
return " = " + r.getBase().quoteString(term); |
public String generateSQL(final SQLSyntax s, final String term) { |
return " = " + s.quoteString(term); |
} |
}; |
static public final SQLSearchMode CONTAINS = new SQLSearchMode() { |
@Override |
public String generateSQL(final DBRoot r, final String term) { |
return " like " + r.getBase().quoteString("%" + SQLSyntax.get(r).getLitteralLikePattern(term) + "%"); |
public List<SQLSearchMode> getHigherModes() { |
return Collections.emptyList(); |
} |
}; |
static public final SQLSearchMode STARTS_WITH = new SQLSearchMode() { |
@Override |
public String generateSQL(final DBRoot r, final String term) { |
return " like " + r.getBase().quoteString(SQLSyntax.get(r).getLitteralLikePattern(term) + "%"); |
public String generateSQL(final SQLSyntax s, final String term) { |
return " like " + s.quoteString(s.getLitteralLikePattern(term) + "%"); |
} |
@Override |
public List<SQLSearchMode> getHigherModes() { |
return Collections.singletonList(EQUALS); |
} |
}; |
static public final SQLSearchMode ENDS_WITH = new SQLSearchMode() { |
@Override |
public String generateSQL(final DBRoot r, final String term) { |
return " like " + r.getBase().quoteString("%" + SQLSyntax.get(r).getLitteralLikePattern(term)); |
public String generateSQL(final SQLSyntax s, final String term) { |
return " like " + s.quoteString("%" + s.getLitteralLikePattern(term)); |
} |
@Override |
public List<SQLSearchMode> getHigherModes() { |
return Collections.singletonList(EQUALS); |
} |
}; |
public abstract String generateSQL(final DBRoot r, final String term); |
private static final List<SQLSearchMode> CONTAINS_HIGHER_MODES = Arrays.asList(EQUALS, STARTS_WITH); |
static public final SQLSearchMode CONTAINS = new SQLSearchMode() { |
@Override |
public String generateSQL(final SQLSyntax s, final String term) { |
return " like " + s.quoteString("%" + s.getLitteralLikePattern(term) + "%"); |
} |
@Override |
public List<SQLSearchMode> getHigherModes() { |
return CONTAINS_HIGHER_MODES; |
} |
}; |
public final String generateSQL(final DBRoot r, final String term) { |
return this.generateSQL(SQLSyntax.get(r), term); |
} |
public abstract String generateSQL(final SQLSyntax s, final String term); |
// from highest to lowest |
public abstract List<SQLSearchMode> getHigherModes(); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/Trigger.java |
---|
13,17 → 13,17 |
package org.openconcerto.sql.model; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.JDOM2Utils; |
import org.openconcerto.xml.XMLCodecUtils; |
import java.util.HashMap; |
import java.util.Map; |
import org.jdom2.Element; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.Immutable; |
import org.jdom2.Element; |
@Immutable |
public final class Trigger { |
82,7 → 82,7 |
public synchronized String toXML() { |
// this is immutable so only compute once the XML |
if (this.xml == null) |
this.xml = "<trigger name=\"" + JDOMUtils.OUTPUTTER.escapeAttributeEntities(getName()) + "\">" + XMLCodecUtils.encodeSimple(this.m) + "</trigger>"; |
this.xml = "<trigger name=\"" + JDOM2Utils.OUTPUTTER.escapeAttributeEntities(getName()) + "\">" + XMLCodecUtils.encodeSimple(this.m) + "</trigger>"; |
return this.xml; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/JDBCStructureSource.java |
---|
113,7 → 113,7 |
// create metadata table here to avoid a second refresh |
// null if we shouldn't alter the base |
final SQLCreateMoveableTable createMetadata = SQLSchema.getCreateMetadata(getBase().getServer().getSQLSystem().getSyntax()); |
final SQLCreateMoveableTable createMetadata = SQLSchema.getCreateMetadata(getBase().getDBSystemRoot().getSyntax()); |
final boolean useCache = getBase().getDBSystemRoot().useCache(); |
Statement stmt = null; |
try { |
271,7 → 271,7 |
} |
// try to find out more about those procedures |
if (proceduresBySchema.size() > 0) { |
final String sel = system.getSyntax().getFunctionQuery(getBase(), proceduresBySchema.keySet()); |
final String sel = getBase().getDBSystemRoot().getSyntax().getFunctionQuery(getBase(), proceduresBySchema.keySet()); |
if (sel != null) { |
// don't cache since we don't listen on system tables |
for (final Object o : (List) getBase().getDataSource().execute(sel, new IResultSetHandler(SQLDataSource.MAP_LIST_HANDLER, false))) { |
321,7 → 321,7 |
@Override |
protected Object getQuery(SQLBase b, TablesMap tables) { |
try { |
return b.getServer().getSQLSystem().getSyntax().getTriggerQuery(b, tables); |
return b.getDBSystemRoot().getSyntax().getTriggerQuery(b, tables); |
} catch (SQLException e) { |
return e; |
} |
340,7 → 340,7 |
@Override |
protected String getQuery(SQLBase b, TablesMap tables) { |
return b.getServer().getSQLSystem().getSyntax().getColumnsQuery(b, tables); |
return b.getDBSystemRoot().getSyntax().getColumnsQuery(b, tables); |
} |
@Override |
357,7 → 357,7 |
@Override |
protected Object getQuery(SQLBase b, TablesMap tables) { |
try { |
return b.getServer().getSQLSystem().getSyntax().getConstraints(b, tables); |
return b.getDBSystemRoot().getSyntax().getConstraints(b, tables); |
} catch (Exception e) { |
return e; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLFilter.java |
---|
71,10 → 71,11 |
private final SQLElementDirectory dir; |
private final GraFFF filterGraph; |
// the filter, from descendant to ancestor |
@GuardedBy("filteredIDs") |
private final List<Set<SQLRow>> filteredIDs; |
// CopyOnWriteArrayList is simpler but rmListener() cannot be implemented |
@GuardedBy("listeners") |
@GuardedBy("this") |
private List<SQLFilterListener> listeners; |
public SQLFilter(SQLElementDirectory dir, final GraFFF filterGraph) { |
192,7 → 193,7 |
} |
final List<SQLFilterListener> dispatchingListeners; |
synchronized (this.listeners) { |
synchronized (this) { |
dispatchingListeners = this.listeners; |
} |
for (final SQLFilterListener l : dispatchingListeners) { |
208,7 → 209,7 |
} |
public void addListener(SQLFilterListener l) { |
synchronized (this.listeners) { |
synchronized (this) { |
final List<SQLFilterListener> newListeners = new ArrayList<SQLFilterListener>(this.listeners.size() + 1); |
newListeners.addAll(this.listeners); |
newListeners.add(l); |
232,7 → 233,7 |
} |
private void rmListener_(SQLFilterListener lToRm) { |
synchronized (this.listeners) { |
synchronized (this) { |
final int stop = this.listeners.size(); |
int indexToRm = -1; |
for (int i = 0; i < stop && indexToRm < 0; i++) { |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesCluster.java |
---|
360,20 → 360,16 |
} |
public final StoreResult insert() throws SQLException { |
return this.insert(false, false); |
return this.store(StoreMode.INSERT); |
} |
public final StoreResult insert(boolean insertPK, boolean insertOrder) throws SQLException { |
return this.store(new Insert(insertPK, insertOrder)); |
} |
public final StoreResult store(final StoreMode mode) throws SQLException { |
return this.store(mode, true); |
return this.store(mode, null); |
} |
// checkValidity false useful when we want to avoid loading the graph |
public final StoreResult store(final StoreMode mode, final boolean checkValidity) throws SQLException { |
return this.store(mode, null, null, checkValidity); |
public final StoreResult store(final StoreMode mode, final Boolean checkValidity) throws SQLException { |
return this.store(mode, null, null, checkValidity, true); |
} |
/** |
383,12 → 379,15 |
* @param start when storing a subset, the start of <code>pruneGraph</code> in this, can be |
* <code>null</code>. |
* @param pruneGraph the maximum graph to store, can be <code>null</code>. |
* @param checkValidity <code>true</code> to check if foreign keys point to valid rows. |
* @param checkValidity whether to ask for checking if foreign keys point to valid rows, see |
* {@link SQLRowValues#setValidityChecked(SQLRowValues.ValidityCheck)}. |
* @param fireEvent <code>false</code> if stored rows shouldn't be fetched and |
* {@link SQLTableEvent} should not be fired. |
* @return the store result. |
* @throws SQLException if an exception occurs. |
* @see {@link #prune(SQLRowValues, SQLRowValues)} |
*/ |
public final StoreResult store(final StoreMode mode, final SQLRowValues start, final SQLRowValues pruneGraph, final boolean checkValidity) throws SQLException { |
public final StoreResult store(final StoreMode mode, final SQLRowValues start, final SQLRowValues pruneGraph, final Boolean checkValidity, final boolean fireEvent) throws SQLException { |
final Map<SQLRowValues, SQLRowValues> prune2orig; |
final SQLRowValuesCluster toStore; |
final boolean prune = pruneGraph != null; |
412,7 → 411,7 |
} |
// check validity first, avoid beginning a transaction for nothing |
// do it after reset otherwise check previous values |
if (checkValidity) |
if (SQLRowValues.isValidityChecked(checkValidity)) |
for (final Node n : nodes.values()) { |
n.noLink.checkValidity(); |
} |
482,9 → 481,9 |
if (n.isStored()) { |
// if there's a cycle, we have to update an already inserted row |
res.add(n.update()); |
res.add(n.update(fireEvent)); |
} else { |
res.add(n.store(mode)); |
res.add(n.store(fireEvent, mode)); |
final SQLRow r = n.getStoredRow(); |
// fill the noLink of referent nodes with the new ID |
499,7 → 498,7 |
// link together the new values |
// if there is a cycle not all foreign keys can be stored at the same time, so |
// wait for the last DB access |
if (lastDBAccess) |
if (lastDBAccess) { |
for (final Map.Entry<String, SQLRowValues> e : toStore.getSrc().getForeigns().entrySet()) { |
final SQLRowValues foreign = nodes.get(e.getValue()).getStoredValues(); |
assert foreign != null : "since this the last db access for this row, all foreigns should have been inserted"; |
508,15 → 507,23 |
throw new IllegalStateException("stored " + n.getStoredValues().getObject(e.getKey()) + " but foreign is " + SQLRowValues.trim(foreign)); |
n.getStoredValues().put(e.getKey(), foreign); |
} |
} |
} |
// all nodes share the same graph, so pick any and freeze the graph |
// null if !fireEvent or if non-rowable table |
final SQLRowValues graphFetched = nodes.values().iterator().next().getStoredValues(); |
if (graphFetched != null) |
graphFetched.getGraph().freeze(); |
return res; |
} |
}); |
// fire events |
for (final SQLTableEvent n : events) { |
// MAYBE put a Map<SQLRowValues, SQLTableEvent> to know how our fellow values have been |
// affected |
n.getTable().fire(n); |
if (fireEvent) { |
for (final SQLTableEvent n : events) { |
// MAYBE put a Map<SQLRowValues, SQLTableEvent> to know how our fellow values have |
// been affected |
n.getTable().fire(n); |
} |
} |
return new StoreResult(res); |
963,6 → 970,7 |
return map; |
} |
// TODO handle referents (and decide how to handle multiple paths to the same node) |
final void grow(final SQLRowValues start, final SQLRowValues toGrow, final boolean checkFields) { |
this.containsCheck(start); |
if (!start.getTable().equals(toGrow.getTable())) |
975,7 → 983,6 |
final SQLRowValues leaf = toGrow.assurePath(input.getPath()); |
if (leaf.hasID()) { |
final SQLRowValuesListFetcher fetcher = new SQLRowValuesListFetcher(input.getCurrent()); |
fetcher.setSelID(leaf.getID()); |
fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() { |
@Override |
public SQLSelect transformChecked(SQLSelect input) { |
985,7 → 992,7 |
return input; |
} |
}); |
final SQLRowValues fetched = CollectionUtils.getSole(fetcher.fetch()); |
final SQLRowValues fetched = fetcher.fetchOne(leaf.getIDNumber()); |
if (fetched == null) |
throw new IllegalArgumentException("no row for " + fetcher); |
leaf.load(fetched, null); |
1524,12 → 1531,19 |
this.noLink = new SQLRowValues(vals, ForeignCopyMode.NO_COPY); |
} |
private SQLTableEvent store(StoreMode mode) throws SQLException { |
private SQLTableEvent store(final boolean fetchStoredRow, StoreMode mode) throws SQLException { |
return this.store(fetchStoredRow, mode, true); |
} |
private SQLTableEvent store(final boolean fetchStoredRow, StoreMode mode, final boolean setRowValues) throws SQLException { |
assert !this.isStored(); |
return this.addEvent(mode.execOn(this.noLink)); |
final SQLTableEvent evt = this.addEvent(mode.execOn(this.noLink, fetchStoredRow)); |
if (fetchStoredRow && evt.getRow() != null && setRowValues) |
evt.setRowValues(evt.getRow().asRowValues()); |
return evt; |
} |
private SQLTableEvent update() throws SQLException { |
private SQLTableEvent update(final boolean fetchStoredRow) throws SQLException { |
assert this.isStored(); |
// fields that have been updated since last store |
1540,13 → 1554,15 |
final SQLRowValues updatingVals = this.getStoredRow().createEmptyUpdateRow(); |
updatingVals.load(this.noLink, fieldsToUpdate); |
final SQLTableEvent evt = new Node(updatingVals).store(StoreMode.COMMIT); |
final SQLTableEvent evt = new Node(updatingVals).store(fetchStoredRow, StoreMode.COMMIT, false); |
// Update previous rowValues, and use it for the new event |
// that way there's only one graph of rowValues (with the final values) for all events. |
// Load all fields since updating 1 field might change the value of another (e.g. |
// with a trigger). |
this.getStoredValues().load(evt.getRow(), null); |
evt.setRowValues(this.getStoredValues()); |
if (fetchStoredRow && evt.getRow() != null) { |
this.getStoredValues().load(evt.getRow(), null); |
evt.setRowValues(this.getStoredValues()); |
} |
return this.addEvent(evt); |
} |
1574,7 → 1590,8 |
} |
private final SQLTableEvent addEvent(SQLTableEvent evt) { |
assert evt != null; |
if (evt == null) |
throw new IllegalStateException("Couldn't update missing row " + this.noLink); |
this.modif.add(evt); |
return evt; |
} |
1591,9 → 1608,11 |
* @author Sylvain |
*/ |
public static abstract class StoreMode { |
abstract SQLTableEvent execOn(SQLRowValues vals) throws SQLException; |
abstract SQLTableEvent execOn(SQLRowValues vals, final boolean fetchStoredRow) throws SQLException; |
public static final StoreMode COMMIT = new Commit(); |
public static final StoreMode INSERT = new Insert(false, false); |
public static final StoreMode INSERT_VERBATIM = new Insert(true, true); |
} |
public static class Insert extends StoreMode { |
1608,20 → 1627,21 |
} |
@Override |
SQLTableEvent execOn(SQLRowValues vals) throws SQLException { |
SQLTableEvent execOn(SQLRowValues vals, final boolean fetchStoredRow) throws SQLException { |
final Set<SQLField> autoFields = new HashSet<SQLField>(); |
if (!this.insertPK) |
autoFields.addAll(vals.getTable().getPrimaryKeys()); |
if (!this.insertOrder) |
autoFields.add(vals.getTable().getOrderField()); |
return vals.insertJustThis(autoFields); |
return vals.insertJustThis(fetchStoredRow, autoFields); |
} |
} |
public static class Commit extends StoreMode { |
@Override |
SQLTableEvent execOn(SQLRowValues vals) throws SQLException { |
return vals.commitJustThis(); |
SQLTableEvent execOn(SQLRowValues vals, final boolean fetchStoredRow) throws SQLException { |
return vals.commitJustThis(fetchStoredRow); |
} |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/Where.java |
---|
14,6 → 14,7 |
package org.openconcerto.sql.model; |
import org.openconcerto.utils.CollectionUtils; |
import org.openconcerto.utils.StringUtils; |
import org.openconcerto.utils.cc.ITransformer; |
import java.util.ArrayList; |
24,10 → 25,10 |
import java.util.Map; |
import java.util.Map.Entry; |
import org.apache.commons.collections.functors.InstanceofPredicate; |
import net.jcip.annotations.Immutable; |
import org.apache.commons.collections.functors.InstanceofPredicate; |
/** |
* Une clause WHERE dans une requete SQL. Une clause peut être facilement combinée avec d'autre, |
* exemple : prenomPasVide.and(pasIndéfini).and(age_sup_3.or(assez_grand)). |
102,6 → 103,10 |
return AndCombiner.combine(where1, where2); |
} |
static public Where or(final Where where1, final Where where2) { |
return OrCombiner.combine(where1, where2); |
} |
static public Where isNull(final FieldRef ref) { |
return new Where(ref, "is", (Object) null); |
} |
144,7 → 149,7 |
static private final String comparison(final FieldRef ref, final String op, final String y) { |
if (op == NULL_IS_DATA_EQ || op == NULL_IS_DATA_NEQ) { |
return ref.getField().getServer().getSQLSystem().getSyntax().getNullIsDataComparison(ref.getFieldRef(), op == NULL_IS_DATA_EQ, y); |
return ref.getField().getDBSystemRoot().getSyntax().getNullIsDataComparison(ref.getFieldRef(), op == NULL_IS_DATA_EQ, y); |
} else { |
return ref.getFieldRef() + " " + op + " " + y; |
} |
261,6 → 266,8 |
// raw ctor, see static methods |
private Where(final String clause, final Collection<? extends FieldRef> refs) { |
if (StringUtils.isEmpty(clause, true)) |
throw new IllegalArgumentException("No clause"); |
this.fields = Collections.unmodifiableList(new ArrayList<FieldRef>(refs)); |
this.clause = clause; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/Constraint.java |
---|
15,7 → 15,7 |
import org.openconcerto.sql.model.SQLSyntax.ConstraintType; |
import org.openconcerto.utils.cc.HashingStrategy; |
import org.openconcerto.xml.JDOMUtils; |
import org.openconcerto.xml.JDOM2Utils; |
import org.openconcerto.xml.XMLCodecUtils; |
import java.util.HashMap; |
22,11 → 22,11 |
import java.util.List; |
import java.util.Map; |
import org.jdom2.Element; |
import net.jcip.annotations.GuardedBy; |
import net.jcip.annotations.Immutable; |
import org.jdom2.Element; |
@Immutable |
public final class Constraint { |
89,7 → 89,7 |
public synchronized String toXML() { |
// this is immutable so only compute once the XML |
if (this.xml == null) |
this.xml = "<constraint name=\"" + JDOMUtils.OUTPUTTER.escapeAttributeEntities(getName()) + "\" >" + XMLCodecUtils.encodeSimple(this.m) + "</constraint>"; |
this.xml = "<constraint name=\"" + JDOM2Utils.OUTPUTTER.escapeAttributeEntities(getName()) + "\" >" + XMLCodecUtils.encodeSimple(this.m) + "</constraint>"; |
return this.xml; |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLServer.java |
---|
247,8 → 247,7 |
final Set<String> allCats; |
final Connection conn = this.getDS().getNewConnection(); |
try { |
@SuppressWarnings("unchecked") |
final List<String> allCatsList = (List<String>) SQLDataSource.COLUMN_LIST_HANDLER.handle(conn.getMetaData().getCatalogs()); |
final List<String> allCatsList = ColumnListHandlerGeneric.create(String.class).handle(conn.getMetaData().getCatalogs()); |
allCats = new HashSet<String>(allCatsList); |
} finally { |
this.getDS().returnConnection(conn); |
417,8 → 416,8 |
final DBSystemRoot sysRoot = this.getDBSystemRoot(); |
if (sysRoot != null && !sysRoot.createNode(this, baseName)) |
throw new IllegalStateException(baseName + " is filtered, you must add it to rootsToMap"); |
final SQLBase base = this.getSQLSystem().getSyntax() |
.createBase(this, baseName, coalesce(systemRootInit, this.systemRootInit), login == null ? this.login : login, pass == null ? this.pass : pass, coalesce(dsInit, this.dsInit)); |
final SQLBase base = new SQLBase(this, baseName, coalesce(systemRootInit, this.systemRootInit), login == null ? this.login : login, pass == null ? this.pass : pass, |
coalesce(dsInit, this.dsInit)); |
return this.putBase(baseName, base, readCache); |
} |
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxMySQL.java |
---|
26,7 → 26,6 |
import org.openconcerto.utils.ListMap; |
import org.openconcerto.utils.StringUtils; |
import org.openconcerto.utils.Tuple2; |
import org.openconcerto.utils.cc.IClosure; |
import org.openconcerto.utils.cc.ITransformer; |
import java.io.BufferedReader; |
48,6 → 47,8 |
import java.util.ArrayList; |
import java.util.Collections; |
import java.util.Date; |
import java.util.HashMap; |
import java.util.IdentityHashMap; |
import java.util.Iterator; |
import java.util.List; |
import java.util.Map; |
63,12 → 64,50 |
* |
* @author Sylvain CUAZ |
*/ |
class SQLSyntaxMySQL extends SQLSyntax { |
public class SQLSyntaxMySQL extends SQLSyntax { |
private static final Pattern INT_PATTERN = Pattern.compile("(bigint|smallint|int)"); |
final static SQLSyntax create(DBSystemRoot sysRoot) { |
final boolean noBackslashEscapes; |
if (sysRoot == null) { |
noBackslashEscapes = false; |
} else { |
final String modes = (String) sysRoot.getDataSource().executeScalar("SELECT @@global.sql_mode;"); |
noBackslashEscapes = modes.contains("NO_BACKSLASH_ESCAPES"); |
} |
return new SQLSyntaxMySQL(noBackslashEscapes); |
} |
SQLSyntaxMySQL() { |
super(SQLSystem.MYSQL); |
static private final IdentityHashMap<String, String> DATE_SPECS; |
static private final Map<Class<?>, String> CAST_TYPES; |
static { |
DATE_SPECS = new IdentityHashMap<String, String>(); |
DATE_SPECS.put(DateProp.YEAR, "%Y"); |
DATE_SPECS.put(DateProp.MONTH_NAME, "%M"); |
DATE_SPECS.put(DateProp.MONTH_NUMBER, "%m"); |
DATE_SPECS.put(DateProp.DAY_IN_MONTH, "%d"); |
DATE_SPECS.put(DateProp.DAY_NAME_IN_WEEK, "%W"); |
DATE_SPECS.put(DateProp.HOUR, "%H"); |
DATE_SPECS.put(DateProp.MINUTE, "%i"); |
DATE_SPECS.put(DateProp.SECOND, "%S"); |
DATE_SPECS.put(DateProp.MICROSECOND, "%f"); |
CAST_TYPES = new HashMap<Class<?>, String>(); |
CAST_TYPES.put(Short.class, "signed integer"); |
CAST_TYPES.put(Integer.class, "signed integer"); |
CAST_TYPES.put(Long.class, "signed integer"); |
CAST_TYPES.put(BigDecimal.class, "decimal"); |
CAST_TYPES.put(Timestamp.class, "datetime"); |
CAST_TYPES.put(java.sql.Date.class, "date"); |
CAST_TYPES.put(java.sql.Time.class, "time"); |
CAST_TYPES.put(Blob.class, "binary"); |
CAST_TYPES.put(String.class, "char"); |
} |
private final boolean noBackslashEscapes; |
public SQLSyntaxMySQL(final boolean noBackslashEscapes) { |
super(SQLSystem.MYSQL, DATE_SPECS); |
this.noBackslashEscapes = noBackslashEscapes; |
this.typeNames.addAll(Boolean.class, "boolean", "bool", "bit"); |
this.typeNames.addAll(Short.class, "smallint"); |
this.typeNames.addAll(Integer.class, "integer", "int"); |
76,8 → 115,9 |
this.typeNames.addAll(BigDecimal.class, "decimal", "numeric"); |
this.typeNames.addAll(Float.class, "float"); |
this.typeNames.addAll(Double.class, "double precision", "real"); |
this.typeNames.addAll(Timestamp.class, "timestamp"); |
this.typeNames.addAll(java.util.Date.class, "time"); |
this.typeNames.addAll(Timestamp.class, "datetime", "timestamp"); |
this.typeNames.addAll(java.sql.Date.class, "date"); |
this.typeNames.addAll(java.sql.Time.class, "time"); |
this.typeNames.addAll(Blob.class, "blob", "tinyblob", "mediumblob", "longblob", "varbinary", "binary"); |
this.typeNames.addAll(Clob.class, "text", "tinytext", "mediumtext", "longtext", "varchar", "char"); |
this.typeNames.addAll(String.class, "varchar", "char"); |
84,6 → 124,21 |
} |
@Override |
public final String quoteString(String s) { |
final String res = super.quoteString(s); |
if (s == null) |
return res; |
// ATTN if noBackslashEscapes is changed for the session, |
// then SQL can be injected : |
// toto \'; drop table ; |
// is quoted to : |
// 'toto \''; drop table ;' |
// and since DDL is not transactional in MySQL the table is forever dropped. |
// escape \ by replacing them with \\ |
return !this.noBackslashEscapes ? SQLSyntaxPG.BACKSLASH_PATTERN.matcher(res).replaceAll(SQLSyntaxPG.TWO_BACKSLASH_REPLACEMENT) : res; |
} |
@Override |
public int getMaximumIdentifierLength() { |
// http://dev.mysql.com/doc/refman/5.7/en/identifiers.html |
return 64; |
104,11 → 159,6 |
} |
@Override |
public String getDateAndTimeType() { |
return "datetime"; |
} |
@Override |
protected String getAutoDateType(SQLField f) { |
return "timestamp"; |
} |
125,9 → 175,9 |
} |
@Override |
public String cast(String expr, String type) { |
public String cast(String expr, Class<?> javaType) { |
// MySQL doesn't use types but keywords |
return super.cast(expr, INT_PATTERN.matcher(type).replaceAll("integer").replace("integer", "signed integer")); |
return this.cast(expr, CAST_TYPES.get(javaType)); |
} |
@Override |
276,13 → 326,12 |
// MySQL dumps strings in binary, so fields must be consistent otherwise the |
// file is invalid |
throw new IllegalArgumentException(t + " has more than on character set : " + charsets); |
final SQLBase base = t.getBase(); |
// if no string cols there should only be values within ASCII (eg dates, ints, etc) |
final String charset = charsets.size() == 0 ? "UTF8" : charsets.keySet().iterator().next(); |
final String cols = CollectionUtils.join(t.getOrderedFields(), ",", new ITransformer<SQLField, String>() { |
@Override |
public String transformChecked(SQLField input) { |
return base.quoteString(input.getName()); |
return quoteString(input.getName()); |
} |
}); |
final File tmp = File.createTempFile(SQLSyntaxMySQL.class.getSimpleName() + "storeData", ".txt"); |
292,7 → 341,7 |
tmp.delete(); |
final SQLSelect sel = new SQLSelect(true).addSelectStar(t); |
// store the data in the temp file |
base.getDataSource().execute("SELECT " + cols + " UNION " + sel.asString() + " INTO OUTFILE " + base.quoteString(tmp.getAbsolutePath()) + " " + getDATA_OPTIONS(base) + ";"); |
t.getDBSystemRoot().getDataSource().execute("SELECT " + cols + " UNION " + sel.asString() + " INTO OUTFILE " + quoteString(tmp.getAbsolutePath()) + " " + getDATA_OPTIONS() + ";"); |
// then read it to remove superfluous escape char and convert to utf8 |
final BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(tmp), charset)); |
Writer w = null; |
342,8 → 391,8 |
} |
} |
private static String getDATA_OPTIONS(final SQLBase b) { |
return "FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY " + b.quoteString("\\") + " LINES TERMINATED BY '\n' "; |
private String getDATA_OPTIONS() { |
return "FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY " + quoteString("\\") + " LINES TERMINATED BY '\n' "; |
} |
@Override |
367,7 → 416,7 |
throw new IllegalStateException("the database charset is not utf8 and this version doesn't support specifying another one : " + dbCharset); |
} |
} |
ds.execute(t.getBase().quote("LOAD DATA LOCAL INFILE %s INTO TABLE %f ", f.getAbsolutePath(), t) + charsetClause + getDATA_OPTIONS(t.getBase()) + " IGNORE 1 LINES;"); |
ds.execute(t.getBase().quote("LOAD DATA LOCAL INFILE %s INTO TABLE %f ", f.getAbsolutePath(), t) + charsetClause + getDATA_OPTIONS() + " IGNORE 1 LINES;"); |
return null; |
} |
}); |
377,11 → 426,6 |
} |
@Override |
SQLBase createBase(SQLServer server, String name, final IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit) { |
return new MySQLBase(server, name, systemRootInit, login, pass, dsInit); |
} |
@Override |
public String getNullIsDataComparison(String x, boolean eq, String y) { |
final String nullSafe = x + " <=> " + y; |
if (eq) |
391,10 → 435,34 |
} |
@Override |
public String getDayOfWeek(String sqlTS) { |
return "DAYOFWEEK(" + sqlTS + ")"; |
} |
@Override |
public String getFormatTimestamp(String sqlTS, boolean basic) { |
return "DATE_FORMAT(" + sqlTS + ", " + SQLBase.quoteStringStd(basic ? "%Y%m%dT%H%i%s.%f" : "%Y-%m-%dT%H:%i:%s.%f") + ")"; |
return this.getFormatTimestamp(sqlTS, SQLBase.quoteStringStd(basic ? "%Y%m%dT%H%i%s.%f" : "%Y-%m-%dT%H:%i:%s.%f")); |
} |
@Override |
public String getFormatTimestamp(String sqlTS, String nativeFormat) { |
return "DATE_FORMAT(" + sqlTS + ", " + nativeFormat + ")"; |
} |
static private final Pattern PERCENT_PATTERN = Pattern.compile("(%+)"); |
@Override |
public String quoteForTimestampFormat(String text) { |
return PERCENT_PATTERN.matcher(text).replaceAll("$1$1"); |
} |
@Override |
public String getConstantTableStatement(List<List<String>> rows, int colCount) { |
if (colCount < 0) |
colCount = rows.get(0).size(); |
return getConstantTable(rows, null, Collections.<String> nCopies(colCount, null)); |
} |
private final void getRow(StringBuilder sb, List<String> row, final int requiredColCount, List<String> columnsAlias) { |
// should be OK since requiredColCount is computed from columnsAlias in getConstantTable() |
assert columnsAlias == null || requiredColCount == columnsAlias.size(); |
403,7 → 471,7 |
throw new IllegalArgumentException("Wrong number of columns, should be " + requiredColCount + " but row is " + row); |
for (int i = 0; i < actualColCount; i++) { |
sb.append(row.get(i)); |
if (columnsAlias != null) { |
if (columnsAlias != null && columnsAlias.get(i) != null) { |
sb.append(" as "); |
sb.append(SQLBase.quoteIdentifier(columnsAlias.get(i))); |
} |
421,7 → 489,9 |
if (colCount < 1) |
throw new IllegalArgumentException("Empty columns will cause a syntax error"); |
final StringBuilder sb = new StringBuilder(rows.size() * 64); |
sb.append("( SELECT "); |
if (alias != null) |
sb.append("( "); |
sb.append("SELECT "); |
// aliases needed only for the first row |
getRow(sb, rows.get(0), colCount, columnsAlias); |
for (int i = 1; i < rowCount; i++) { |
428,8 → 498,10 |
sb.append("\nUNION ALL\nSELECT "); |
getRow(sb, rows.get(i), colCount, null); |
} |
sb.append(" ) as "); |
sb.append(SQLBase.quoteIdentifier(alias)); |
if (alias != null) { |
sb.append(" ) as "); |
sb.append(SQLBase.quoteIdentifier(alias)); |
} |
return sb.toString(); |
} |
< |