OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 93 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 93 Rev 177
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
9
 * language governing permissions and limitations under the License.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.sql.view.list.search;
14
 package org.openconcerto.sql.view.list.search;
15
 
15
 
16
import org.openconcerto.sql.model.graph.Link.Direction;
16
import org.openconcerto.sql.model.graph.Link.Direction;
17
import org.openconcerto.sql.model.graph.Path;
17
import org.openconcerto.sql.model.graph.Path;
18
import org.openconcerto.sql.model.graph.Step;
18
import org.openconcerto.sql.model.graph.Step;
19
import org.openconcerto.sql.view.list.ITableModel;
19
import org.openconcerto.sql.view.list.ITableModel;
20
import org.openconcerto.sql.view.list.ListAccess;
20
import org.openconcerto.sql.view.list.ListAccess;
21
import org.openconcerto.sql.view.list.ListSQLLine;
21
import org.openconcerto.sql.view.list.ListSQLLine;
22
import org.openconcerto.sql.view.list.UpdateQueue;
22
import org.openconcerto.sql.view.list.UpdateQueue;
23
import org.openconcerto.sql.view.list.UpdateQueue.TaskType;
23
import org.openconcerto.sql.view.list.UpdateQueue.TaskType;
24
import org.openconcerto.sql.view.list.search.SearchOne.Mode;
24
import org.openconcerto.sql.view.list.search.SearchOne.Mode;
25
import org.openconcerto.sql.view.search.SearchSpec;
25
import org.openconcerto.sql.view.search.SearchSpec;
26
import org.openconcerto.utils.IFutureTask;
26
import org.openconcerto.utils.IFutureTask;
27
import org.openconcerto.utils.SleepingQueue;
27
import org.openconcerto.utils.SleepingQueue;
28
import org.openconcerto.utils.cc.IClosure;
28
import org.openconcerto.utils.cc.IClosure;
29
import org.openconcerto.utils.cc.ITransformer;
29
import org.openconcerto.utils.cc.ITransformer;
30
 
30
 
31
import java.util.Collection;
31
import java.util.Collection;
32
import java.util.Deque;
32
import java.util.Deque;
33
import java.util.concurrent.FutureTask;
33
import java.util.concurrent.RunnableFuture;
34
 
34
 
35
import javax.swing.SwingUtilities;
35
import javax.swing.SwingUtilities;
36
 
36
 
37
public final class SearchQueue extends SleepingQueue {
37
public final class SearchQueue extends SleepingQueue {
38
 
38
 
39
    static public interface SetStateRunnable extends Runnable {
39
    static public interface SetStateRunnable extends Runnable {
40
    }
40
    }
41
 
41
 
42
    /**
42
    /**
43
     * Whether the passed future performs a search.
43
     * Whether the passed future performs a search.
44
     * 
44
     * 
45
     * @param f a task in this queue, can be <code>null</code>.
45
     * @param f a task in this queue, can be <code>null</code>.
46
     * @return <code>true</code> if <code>f</code> searches.
46
     * @return <code>true</code> if <code>f</code> searches.
47
     */
47
     */
48
    public static boolean isSearch(final FutureTask<?> f) {
48
    public static boolean isSearch(final RunnableFuture<?> f) {
49
        final Runnable r = getRunnable(f);
49
        final Runnable r = getRunnable(f);
50
        return r instanceof SearchRunnable && ((SearchRunnable) r).performsSearch();
50
        return r instanceof SearchRunnable && ((SearchRunnable) r).performsSearch();
51
    }
51
    }
52
 
52
 
53
    public static Runnable getRunnable(final FutureTask<?> f) {
53
    public static Runnable getRunnable(final RunnableFuture<?> f) {
54
        if (f instanceof IFutureTask)
54
        if (f instanceof IFutureTask)
55
            return ((IFutureTask<?>) f).getRunnable();
55
            return ((IFutureTask<?>) f).getRunnable();
56
        else
56
        else
57
            return null;
57
            return null;
58
    }
58
    }
59
 
59
 
60
    /**
60
    /**
61
     * The last referent step of the passed path.
61
     * The last referent step of the passed path.
62
     * 
62
     * 
63
     * @param p a path.
63
     * @param p a path.
64
     * @return the name of the field of the last referent step, <code>null</code> if it doesn't
64
     * @return the name of the field of the last referent step, <code>null</code> if it doesn't
65
     *         exist.
65
     *         exist.
66
     */
66
     */
67
    public static String getLastReferentField(final Path p) {
67
    public static String getLastReferentField(final Path p) {
68
        final Step lastStep = p.length() == 0 ? null : p.getStep(-1);
68
        final Step lastStep = p.length() == 0 ? null : p.getStep(-1);
69
        final boolean lastIsForeign = lastStep == null || lastStep.getDirection() == Direction.FOREIGN;
69
        final boolean lastIsForeign = lastStep == null || lastStep.getDirection() == Direction.FOREIGN;
70
        return lastIsForeign ? null : lastStep.getSingleField().getName();
70
        return lastIsForeign ? null : lastStep.getSingleField().getName();
71
    }
71
    }
72
 
72
 
73
    private final ITableModel model;
73
    private final ITableModel model;
74
    // only accessed within this queue
74
    // only accessed within this queue
75
    SearchSpec search;
75
    SearchSpec search;
76
    private final ListAccess listAccess;
76
    private final ListAccess listAccess;
77
    // thread-safe
77
    // thread-safe
78
    private final IClosure<Deque<FutureTask<?>>> cancelClosure;
78
    private final IClosure<Deque<RunnableFuture<?>>> cancelClosure;
79
 
79
 
80
    public SearchQueue(final ListAccess la) {
80
    public SearchQueue(final ListAccess la) {
81
        super(SearchQueue.class.getName() + " on " + la.getModel());
81
        super(SearchQueue.class.getName() + " on " + la.getModel());
82
        this.listAccess = la;
82
        this.listAccess = la;
83
        this.model = la.getModel();
83
        this.model = la.getModel();
84
        this.search = null;
84
        this.search = null;
85
        this.cancelClosure = UpdateQueue.createCancelClosure(this, new ITransformer<FutureTask<?>, TaskType>() {
85
        this.cancelClosure = UpdateQueue.createCancelClosure(this, new ITransformer<RunnableFuture<?>, TaskType>() {
86
            @Override
86
            @Override
87
            public TaskType transformChecked(FutureTask<?> input) {
87
            public TaskType transformChecked(RunnableFuture<?> input) {
88
                final Runnable r = getRunnable(input);
88
                final Runnable r = getRunnable(input);
89
                if (r instanceof SearchRunnable)
89
                if (r instanceof SearchRunnable)
90
                    return TaskType.COMPUTE;
90
                    return TaskType.COMPUTE;
91
                else if (r instanceof SetStateRunnable)
91
                else if (r instanceof SetStateRunnable)
92
                    return TaskType.SET_STATE;
92
                    return TaskType.SET_STATE;
93
                else
93
                else
94
                    return TaskType.USER;
94
                    return TaskType.USER;
95
            }
95
            }
96
        });
96
        });
97
    }
97
    }
98
 
98
 
99
    public void orderChanged() {
99
    public void orderChanged() {
100
        // don't search all if only order has changed
100
        // don't search all if only order has changed
101
        this.put(new SearchRunnable(this) {
101
        this.put(new SearchRunnable(this) {
102
 
102
 
103
            @Override
103
            @Override
104
            protected boolean performsSearch() {
104
            protected boolean performsSearch() {
105
                return false;
105
                return false;
106
            }
106
            }
107
 
107
 
108
            @Override
108
            @Override
109
            public void run() {
109
            public void run() {
110
                SwingUtilities.invokeLater(new Runnable() {
110
                SwingUtilities.invokeLater(new Runnable() {
111
                    @Override
111
                    @Override
112
                    public void run() {
112
                    public void run() {
113
                        getAccess().setList(null, null);
113
                        getAccess().setList(null, null);
114
                    }
114
                    }
115
                });
115
                });
116
            }
116
            }
117
        });
117
        });
118
    }
118
    }
119
 
119
 
120
    public void changeFullList(final int id, final ListSQLLine modifiedLine, final Collection<Integer> modifiedCols, final Mode mode) {
120
    public void changeFullList(final int id, final ListSQLLine modifiedLine, final Collection<Integer> modifiedCols, final Mode mode) {
121
        final SearchOne oneSearchRunnable = new SearchOne(this, id, modifiedLine, modifiedCols, mode);
121
        final SearchOne oneSearchRunnable = new SearchOne(this, id, modifiedLine, modifiedCols, mode);
122
        this.put(oneSearchRunnable);
122
        this.put(oneSearchRunnable);
123
    }
123
    }
124
 
124
 
125
    public void fullListChanged() {
125
    public void fullListChanged() {
126
        fullDataChange();
126
        fullDataChange();
127
    }
127
    }
128
 
128
 
129
    public void setSearch(final SearchSpec s) {
129
    public void setSearch(final SearchSpec s) {
130
        this.setSearch(s, null);
130
        this.setSearch(s, null);
131
    }
131
    }
132
 
132
 
133
    public void setSearch(final SearchSpec s, final Runnable r) {
133
    public void setSearch(final SearchSpec s, final Runnable r) {
134
        // needs to be 2 different runnables, that way if the search is changed and then the table
134
        // needs to be 2 different runnables, that way if the search is changed and then the table
135
        // is updated : the queue would naively contain setSearch, searchAll, searchAll and thus we
135
        // is updated : the queue would naively contain setSearch, searchAll, searchAll and thus we
136
        // can cancel one searchAll. Whereas if the setSearch was contained in searchAll, we
136
        // can cancel one searchAll. Whereas if the setSearch was contained in searchAll, we
137
        // couldn't cancel it.
137
        // couldn't cancel it.
138
        // use tasksDo() so that no other runnable can come between setSearch and searchAll.
138
        // use tasksDo() so that no other runnable can come between setSearch and searchAll.
139
        // Otherwise a runnable might the new search query but not the new filtered list.
139
        // Otherwise a runnable might the new search query but not the new filtered list.
140
        this.tasksDo(new IClosure<Deque<FutureTask<?>>>() {
140
        this.tasksDo(new IClosure<Deque<RunnableFuture<?>>>() {
141
            @Override
141
            @Override
142
            public void executeChecked(Deque<FutureTask<?>> input) {
142
            public void executeChecked(Deque<RunnableFuture<?>> input) {
143
                put(new SetStateRunnable() {
143
                put(new SetStateRunnable() {
144
                    @Override
144
                    @Override
145
                    public void run() {
145
                    public void run() {
146
                        SearchQueue.this.search = s;
146
                        SearchQueue.this.search = s;
147
                    }
147
                    }
148
                });
148
                });
149
                fullDataChange();
149
                fullDataChange();
150
                if (r != null) {
150
                if (r != null) {
151
                    put(new Runnable() {
151
                    put(new Runnable() {
152
                        @Override
152
                        @Override
153
                        public void run() {
153
                        public void run() {
154
                            SwingUtilities.invokeLater(r);
154
                            SwingUtilities.invokeLater(r);
155
                        }
155
                        }
156
                    });
156
                    });
157
                }
157
                }
158
            }
158
            }
159
        });
159
        });
160
    }
160
    }
161
 
161
 
162
    private void fullDataChange() {
162
    private void fullDataChange() {
163
        this.put(new SearchAll(this));
163
        this.put(new SearchAll(this));
164
    }
164
    }
165
 
165
 
166
    @Override
166
    @Override
167
    protected void willPut(final FutureTask<?> qr) throws InterruptedException {
167
    protected void willPut(final RunnableFuture<?> qr) throws InterruptedException {
168
        if (getRunnable(qr) instanceof SearchAll) {
168
        if (getRunnable(qr) instanceof SearchAll) {
169
            // si on recherche tout, ne sert à rien de garder les recherches précédentes.
169
            // si on recherche tout, ne sert à rien de garder les recherches précédentes.
170
            this.tasksDo(this.cancelClosure);
170
            this.tasksDo(this.cancelClosure);
171
        }
171
        }
172
    }
172
    }
173
 
173
 
174
    @Override
174
    @Override
175
    public String toString() {
175
    public String toString() {
176
        return this.getClass().getName() + " for " + this.getModel();
176
        return this.getClass().getName() + " for " + this.getModel();
177
    }
177
    }
178
 
178
 
179
    final SearchSpec getSearch() {
179
    final SearchSpec getSearch() {
180
        return this.search;
180
        return this.search;
181
    }
181
    }
182
 
182
 
183
    final ListAccess getAccess() {
183
    final ListAccess getAccess() {
184
        return this.listAccess;
184
        return this.listAccess;
185
    }
185
    }
186
 
186
 
187
    public final ITableModel getModel() {
187
    public final ITableModel getModel() {
188
        return this.model;
188
        return this.model;
189
    }
189
    }
190
}
190
}