OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 177 | Details | Compare with Previous | Last modification | View Log | RSS feed

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