OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 93 | 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
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
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) {
68
        final Step lastStep = p.length() == 0 ? null : p.getStep(-1);
69
        final boolean lastIsForeign = lastStep == null || lastStep.getDirection() == Direction.FOREIGN;
70
        return lastIsForeign ? null : lastStep.getSingleField().getName();
71
    }
72
 
17 ilm 73
    private final ITableModel model;
93 ilm 74
    // only accessed within this queue
17 ilm 75
    SearchSpec search;
76
    private final ListAccess listAccess;
93 ilm 77
    // thread-safe
177 ilm 78
    private final IClosure<Deque<RunnableFuture<?>>> cancelClosure;
17 ilm 79
 
80
    public SearchQueue(final ListAccess la) {
81
        super(SearchQueue.class.getName() + " on " + la.getModel());
82
        this.listAccess = la;
83
        this.model = la.getModel();
84
        this.search = null;
177 ilm 85
        this.cancelClosure = UpdateQueue.createCancelClosure(this, new ITransformer<RunnableFuture<?>, TaskType>() {
17 ilm 86
            @Override
177 ilm 87
            public TaskType transformChecked(RunnableFuture<?> input) {
93 ilm 88
                final Runnable r = getRunnable(input);
89
                if (r instanceof SearchRunnable)
90
                    return TaskType.COMPUTE;
91
                else if (r instanceof SetStateRunnable)
92
                    return TaskType.SET_STATE;
93
                else
94
                    return TaskType.USER;
17 ilm 95
            }
93 ilm 96
        });
17 ilm 97
    }
98
 
93 ilm 99
    public void orderChanged() {
100
        // don't search all if only order has changed
101
        this.put(new SearchRunnable(this) {
17 ilm 102
 
103
            @Override
93 ilm 104
            protected boolean performsSearch() {
105
                return false;
17 ilm 106
            }
107
 
93 ilm 108
            @Override
109
            public void run() {
110
                SwingUtilities.invokeLater(new Runnable() {
111
                    @Override
112
                    public void run() {
113
                        getAccess().setList(null, null);
17 ilm 114
                    }
93 ilm 115
                });
17 ilm 116
            }
93 ilm 117
        });
17 ilm 118
    }
119
 
93 ilm 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);
122
        this.put(oneSearchRunnable);
83 ilm 123
    }
124
 
93 ilm 125
    public void fullListChanged() {
126
        fullDataChange();
17 ilm 127
    }
128
 
93 ilm 129
    public void setSearch(final SearchSpec s) {
130
        this.setSearch(s, null);
17 ilm 131
    }
132
 
93 ilm 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
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
137
        // couldn't cancel it.
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.
177 ilm 140
        this.tasksDo(new IClosure<Deque<RunnableFuture<?>>>() {
93 ilm 141
            @Override
177 ilm 142
            public void executeChecked(Deque<RunnableFuture<?>> input) {
93 ilm 143
                put(new SetStateRunnable() {
144
                    @Override
145
                    public void run() {
146
                        SearchQueue.this.search = s;
147
                    }
148
                });
149
                fullDataChange();
150
                if (r != null) {
151
                    put(new Runnable() {
152
                        @Override
153
                        public void run() {
154
                            SwingUtilities.invokeLater(r);
155
                        }
156
                    });
157
                }
17 ilm 158
            }
159
        });
160
    }
161
 
93 ilm 162
    private void fullDataChange() {
163
        this.put(new SearchAll(this));
17 ilm 164
    }
165
 
93 ilm 166
    @Override
177 ilm 167
    protected void willPut(final RunnableFuture<?> qr) throws InterruptedException {
93 ilm 168
        if (getRunnable(qr) instanceof SearchAll) {
169
            // si on recherche tout, ne sert à rien de garder les recherches précédentes.
170
            this.tasksDo(this.cancelClosure);
171
        }
17 ilm 172
    }
173
 
93 ilm 174
    @Override
17 ilm 175
    public String toString() {
176
        return this.getClass().getName() + " for " + this.getModel();
177
    }
178
 
179
    final SearchSpec getSearch() {
180
        return this.search;
181
    }
182
 
183
    final ListAccess getAccess() {
184
        return this.listAccess;
185
    }
186
 
187
    public final ITableModel getModel() {
188
        return this.model;
189
    }
190
}