OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 177 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
174 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.
174 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.ui.grid;
15
 
16
import java.awt.BasicStroke;
17
import java.awt.Color;
18
import java.awt.Dimension;
19
import java.awt.Graphics;
20
import java.awt.Graphics2D;
177 ilm 21
import java.awt.Rectangle;
174 ilm 22
import java.awt.event.MouseAdapter;
23
import java.awt.event.MouseEvent;
24
import java.awt.event.MouseMotionListener;
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.HashSet;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Set;
31
 
32
import javax.swing.JFrame;
33
import javax.swing.SwingUtilities;
34
import javax.swing.UIManager;
35
import javax.swing.UnsupportedLookAndFeelException;
36
 
177 ilm 37
public class GridPanel extends ScrollablePanel {
174 ilm 38
    private static final Color SELECTION_BORDER_COLOR = new Color(200, 210, 220, 250);
39
    private static final Color SELECTION_COLOR = new Color(230, 240, 250, 180);
40
    private static final Color CREATION_COLOR = new Color(250, 254, 30, 100);
41
    private static final Color CREATION_BORDER_COLOR = new Color(250, 254, 60, 180);
42
 
43
    private int cellWidth = 40;
44
    private final int cellHeight;
45
    private int gridLineWidth = 1;
46
    private Color gridVerticalColor = Color.LIGHT_GRAY;
47
    private Color gridHorizontalColor = Color.DARK_GRAY;
48
    private int columnCount;
49
    private int rowCount;
50
    private List<GridItem> items = new ArrayList<>();
51
    private Map<Integer, List<GridItem>> itemsByRow = new HashMap<>();
52
 
53
    protected GridItem onCreationItem;
54
    protected int onCreationX;
55
    protected boolean[] onCreationAllowedColumns;
56
    private boolean editMode;
57
    protected GridListener gridListener;
58
    private Set<GridItem> selectedItems = new HashSet<>();
59
 
60
    public GridPanel(int columnCount, int rowCount) {
61
        this(columnCount, rowCount, 40);
62
    }
63
 
64
    public GridPanel(int columnCount, int rowCount, int rowHeight) {
65
        this.setBackground(Color.WHITE);
66
        this.rowCount = rowCount;
67
        this.columnCount = columnCount;
68
        this.cellHeight = rowHeight;
69
        this.addMouseMotionListener(new MouseMotionListener() {
70
 
71
            @Override
72
            public void mouseMoved(MouseEvent e) {
73
                // nothing
74
            }
75
 
76
            @Override
77
            public void mouseDragged(MouseEvent e) {
78
                if (GridPanel.this.onCreationItem != null) {
79
 
80
                    int x = getColumnFromMouseX(e.getX());
81
                    if (x >= 0 && x < columnCount && GridPanel.this.onCreationAllowedColumns[x]) {
82
                        if (x > GridPanel.this.onCreationX) {
83
                            GridPanel.this.onCreationItem.setW(x - GridPanel.this.onCreationX + 1);
84
                        } else {
85
                            GridPanel.this.onCreationItem.setX(x);
86
                            GridPanel.this.onCreationItem.setW(GridPanel.this.onCreationX - x + 1);
87
                        }
88
                    }
89
                    repaint();
90
 
91
                }
92
 
93
            }
94
        });
95
        this.addMouseListener(new MouseAdapter() {
96
 
97
            @Override
98
            public void mouseReleased(MouseEvent e) {
99
                final GridItem selectedItem = getItemAtMouse(e.getX(), e.getY());
100
                if (!e.isControlDown()) {
101
                    GridPanel.this.selectedItems.clear();
102
                }
103
                if (selectedItem != null) {
104
                    if (GridPanel.this.selectedItems.contains(selectedItem) && !e.isPopupTrigger()) {
105
                        GridPanel.this.selectedItems.remove(selectedItem);
106
                    } else {
107
                        GridPanel.this.selectedItems.add(selectedItem);
108
                    }
109
                }
110
 
111
                if (GridPanel.this.onCreationItem != null) {
112
                    // Add the item
113
                    GridItem newItem = new GridItem(GridPanel.this.onCreationItem.getX(), GridPanel.this.onCreationItem.getY(), GridPanel.this.onCreationItem.getW(),
114
                            GridPanel.this.onCreationItem.getH());
115
                    if (GridPanel.this.gridListener != null) {
116
                        boolean added = GridPanel.this.gridListener.add(GridPanel.this, newItem);
117
                        if (added) {
118
                            add(newItem);
119
                        }
120
                    }
121
                    //
122
                    GridPanel.this.onCreationItem = null;
123
 
124
                }
125
                repaint();
126
                if (GridPanel.this.gridListener != null && e.isPopupTrigger()) {
127
                    GridPanel.this.gridListener.triggerPopup(GridPanel.this, e.getX(), e.getY());
128
                }
129
            }
130
 
131
            @Override
132
            public void mousePressed(MouseEvent e) {
133
                final GridItem selectedItem = getItemAtMouse(e.getX(), e.getY());
134
                if (GridPanel.this.editMode && selectedItem == null && getRowFromMouseY(e.getY()) < rowCount) {
135
                    GridPanel.this.onCreationX = getColumnFromMouseX(e.getX());
136
                    GridPanel.this.onCreationAllowedColumns = new boolean[columnCount];
137
                    GridPanel.this.onCreationAllowedColumns[GridPanel.this.onCreationX] = true;
138
                    final int onCreationY = getRowFromMouseY(e.getY());
139
                    for (int i = GridPanel.this.onCreationX + 1; i < columnCount; i++) {
140
                        if (getItem(onCreationY, i) == null) {
141
                            GridPanel.this.onCreationAllowedColumns[i] = true;
142
                        } else {
143
                            break;
144
                        }
145
                    }
146
                    for (int i = GridPanel.this.onCreationX - 1; i >= 0; i--) {
147
                        if (getItem(onCreationY, i) == null) {
148
                            GridPanel.this.onCreationAllowedColumns[i] = true;
149
                        } else {
150
                            break;
151
                        }
152
                    }
153
                    GridPanel.this.onCreationItem = new GridItem(getColumnFromMouseX(e.getX()), onCreationY, 1, 1);
154
                    GridPanel.this.onCreationItem.setColor(CREATION_COLOR);
155
                    GridPanel.this.onCreationItem.setBorderColor(CREATION_BORDER_COLOR);
156
 
157
                }
158
                repaint();
159
                if (GridPanel.this.gridListener != null) {
160
                    GridPanel.this.gridListener.selectionChanged(GridPanel.this);
161
                    if (e.isPopupTrigger()) {
162
                        GridPanel.this.gridListener.triggerPopup(GridPanel.this, e.getX(), e.getY());
163
                    }
164
                }
165
            }
166
 
167
        });
168
 
169
    }
170
 
171
    public void add(GridItem item) {
172
        this.items.add(item);
173
        for (int n = 0; n < item.getH(); n++) {
174
            final int y = item.getY() + n;
175
            List<GridItem> list = this.itemsByRow.get(y);
176
            if (list == null) {
177
                list = new ArrayList<>();
178
                list.add(item);
179
                this.itemsByRow.put(Integer.valueOf(y), list);
180
            }
181
            list.add(item);
182
        }
183
    }
184
 
185
    public int getCellHeight() {
186
        return this.cellHeight;
187
    }
188
 
189
    @Override
190
    public Dimension getPreferredSize() {
191
        return new Dimension(this.columnCount * this.cellWidth + (1 + this.columnCount) * this.gridLineWidth, this.rowCount * this.cellWidth + (1 + this.rowCount) * this.gridLineWidth);
192
    }
193
 
194
    @Override
195
    public Dimension getMinimumSize() {
196
        return getPreferredSize();
197
    }
198
 
199
    @Override
200
    public Dimension getMaximumSize() {
201
        return getPreferredSize();
202
    }
203
 
204
    @Override
205
    protected void paintComponent(Graphics g) {
206
        super.paintComponent(g);
207
 
208
        int x = 0;
209
        final int h = this.getHeight();
210
        Graphics2D g2 = (Graphics2D) g;
211
        g2.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 4 }, 0));
212
        // Vertical lines
213
        g.setColor(this.gridVerticalColor);
214
        for (int i = 0; i <= this.columnCount; i++) {
215
            g.drawLine(x, 0, x, h);
216
            x += this.gridLineWidth + this.cellWidth;
217
        }
218
        // Horizontal lines
219
        g.setColor(this.gridHorizontalColor);
220
        int w = this.getWidth();
221
        int y = 0;
222
        for (int i = 0; i <= this.rowCount; i++) {
223
            g.drawLine(0, y, w, y);
224
            y += this.gridLineWidth + this.cellHeight;
225
        }
226
        g2.setStroke(new BasicStroke(1));
227
        for (GridItem item : this.items) {
228
            drawItem(g, item);
229
        }
230
        if (this.onCreationItem != null) {
231
            drawItem(g, this.onCreationItem);
232
        }
233
 
234
    }
235
 
236
    private void drawItem(Graphics g, GridItem item) {
237
        final boolean isSelected = this.selectedItems.contains(item);
238
        if (isSelected) {
239
            g.setColor(SELECTION_COLOR);
240
        } else {
241
            g.setColor(item.getColor());
242
        }
243
        int width = item.getW() * (this.gridLineWidth + this.cellWidth);
244
        int height = item.getH() * (this.gridLineWidth + this.cellHeight);
245
        final int itemX = item.getX() * (this.gridLineWidth + this.cellWidth);
246
        final int itemY = item.getY() * (this.gridLineWidth + this.cellHeight);
247
        g.fillRect(itemX + 1, itemY + 1, width - 2, height - 2);
248
        if (isSelected) {
249
            g.setColor(SELECTION_BORDER_COLOR);
250
        } else {
251
            g.setColor(item.getBorderColor());
252
        }
253
        g.drawRect(itemX + 1, itemY + 1, width - 2, height - 2);
254
        g.drawRect(itemX, itemY, width, height);
255
    }
256
 
257
    public static void main(String[] args) {
258
        SwingUtilities.invokeLater(new Runnable() {
259
 
260
            @Override
261
            public void run() {
262
                try {
263
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
264
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
265
                    //
266
                }
267
                JFrame f = new JFrame();
268
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
269
                final GridPanel contentPane = new GridPanel(24, 4);
270
                contentPane.add(new GridItem(0, 0, 1, 1));
271
                contentPane.add(new GridItem(4, 0, 3, 1));
272
                contentPane.add(new GridItem(1, 1, 2, 2));
273
                f.setContentPane(contentPane);
274
                f.pack();
275
                f.setLocationRelativeTo(null);
276
                f.setVisible(true);
277
            }
278
        });
279
    }
280
 
281
    GridItem getItemAtMouse(int x, int y) {
282
        int row = getRowFromMouseY(y);
283
        int col = getColumnFromMouseX(x);
284
        return getItem(row, col);
285
    }
286
 
287
    private GridItem getItem(int row, int col) {
288
        List<GridItem> rItems = this.itemsByRow.get(row);
289
        if (rItems == null) {
290
            return null;
291
        }
292
        for (GridItem item : rItems) {
293
            if (item.getX() <= col && (item.getX() + item.getW()) > col) {
294
                return item;
295
            }
296
        }
297
        return null;
298
    }
299
 
300
    private int getColumnFromMouseX(int x) {
301
        return x / (this.gridLineWidth + this.cellWidth);
302
    }
303
 
304
    private int getRowFromMouseY(int y) {
305
        return y / (this.gridLineWidth + this.cellHeight);
306
    }
307
 
308
    public void setEnableEditMode(boolean enable) {
309
        this.editMode = enable;
310
    }
311
 
312
    public void setGridListener(GridListener gridListener) {
313
        this.gridListener = gridListener;
314
    }
315
 
316
    public List<GridItem> getSelectedItems() {
317
        return new ArrayList<>(this.selectedItems);
318
    }
177 ilm 319
 
320
    @Override
321
    public Dimension getPreferredScrollableViewportSize() {
322
        // TODO Auto-generated method stub
323
        return null;
324
    }
325
 
326
    @Override
327
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
328
        // TODO Auto-generated method stub
329
        return 40;
330
    }
331
 
332
    @Override
333
    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
334
        // TODO Auto-generated method stub
335
        return 40;
336
    }
337
 
338
    @Override
339
    public boolean getScrollableTracksViewportWidth() {
340
        // TODO Auto-generated method stub
341
        return false;
342
    }
343
 
344
    @Override
345
    public boolean getScrollableTracksViewportHeight() {
346
        // TODO Auto-generated method stub
347
        return false;
348
    }
174 ilm 349
}