This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 78605
Collapse All | Expand All

(-)progress/manifest.mf (+1 lines)
Line 6 Link Here
6
OpenIDE-Module-Needs: org.netbeans.spi.progress.ProgressUIWorkerProvider
(-)progress/api/doc/changes/apichanges.xml (+14 lines)
Line 87 Link Here
87
        <summary>Split APi and implementation of progress compoennt</summary>
88
        <version major="1" minor="7"/>
89
        <date day="24" month="7" year="2006"/>
90
        <author login="mkleint"/>
91
        <compatibility addition="yes"/>
92
        <description>
93
            <p>
94
                Split the implementation and APIs of progress component.
95
            </p>
96
        </description>
97
        <issue number="78605"/>
98
    </change>      
99
    <change>
100
        <api name="progress_api"/>
(-)progress/nbproject/project.properties (-2 / +1 lines)
Line 21 Link Here
21
spec.version.base=1.6.0
21
spec.version.base=1.7.0
22
--
(-)progress/nbproject/project.xml (-18 / +11 lines)
Line 34 Link Here
34
            <dependency>
34
                <dependency>
35
--
Lines 42-57 Link Here
42
            <dependency>
43
                    <code-name-base>org.openide.dialogs</code-name-base>
44
                    <build-prerequisite/>
45
                    <compile-dependency/>
46
                    <run-dependency>
47
                        <specification-version>6.2</specification-version>
48
                    </run-dependency>
49
                </dependency>
50
            <dependency>
51
                    <code-name-base>org.openide.windows</code-name-base>
52
                    <build-prerequisite/>
53
                    <compile-dependency/>
54
                    <run-dependency>
55
                        <specification-version>6.2</specification-version>
56
                    </run-dependency>
57
                </dependency>
Line 59 Link Here
43
          <test-dependencies>
44
              <test-type>
45
                  <name>unit</name>
46
                  <test-dependency>
47
                      <code-name-base>org.netbeans.modules.progress.ui</code-name-base>
48
                      <!--recursive/-->
49
                      <compile-dependency/>
50
                  </test-dependency>
51
              </test-type>
52
          </test-dependencies>
(-)progress/src/org/netbeans/api/progress/ProgressHandle.java (-2 / +1 lines)
Line 29 Link Here
29
import org.netbeans.progress.module.InternalHandle;
29
import org.netbeans.progress.spi.InternalHandle;
30
--
(-)progress/src/org/netbeans/api/progress/ProgressHandleFactory.java (-2 / +1 lines)
Line 24 Link Here
24
import org.netbeans.progress.module.InternalHandle;
24
import org.netbeans.progress.spi.InternalHandle;
25
--
(-)progress/src/org/netbeans/api/progress/aggregate/AggregateProgressFactory.java (-2 / +1 lines)
Line 24 Link Here
24
import org.netbeans.progress.module.InternalHandle;
24
import org.netbeans.progress.spi.InternalHandle;
25
--
(-)progress/src/org/netbeans/progress/module/Controller.java (-21 / +18 lines)
Lines 37-38 Link Here
37
import org.netbeans.progress.module.ui.StatusLineComponent;
37
import org.netbeans.progress.spi.InternalHandle;
38
import org.openide.windows.WindowManager;
38
import org.netbeans.progress.spi.ProgressEvent;
39
--
39
import org.netbeans.progress.spi.ProgressUIWorker;
40
import org.netbeans.progress.spi.ProgressUIWorkerProvider;
41
import org.netbeans.progress.spi.ProgressUIWorkerWithModel;
42
import org.netbeans.progress.spi.TaskModel;
43
import org.openide.util.Lookup;
Line 75 Link Here
75
            StatusLineComponent component = new StatusLineComponent();
80
            ProgressUIWorkerProvider prov = (ProgressUIWorkerProvider)Lookup.getDefault().lookup(ProgressUIWorkerProvider.class); 
76
--
81
            assert prov != null;
82
            ProgressUIWorkerWithModel component = prov.getDefaultWorker();
Line 94 Link Here
94
    void start(InternalHandle handle) {
101
    public void start(InternalHandle handle) {
95
--
Line 104 Link Here
104
    void finish(InternalHandle handle) {
111
    public void finish(InternalHandle handle) {
105
--
Line 109 Link Here
109
    void toIndeterminate(InternalHandle handle) {
116
    public void toIndeterminate(InternalHandle handle) {
110
--
Line 114 Link Here
114
    void toDeterminate(InternalHandle handle) {
121
    public void toDeterminate(InternalHandle handle) {
115
--
Line 119 Link Here
119
    void progress(InternalHandle handle, String msg, 
126
    public void progress(InternalHandle handle, String msg, 
120
--
Line 125 Link Here
125
    ProgressEvent snapshot(InternalHandle handle, String msg, 
132
    public ProgressEvent snapshot(InternalHandle handle, String msg, 
126
--
Line 131 Link Here
131
    void explicitSelection(InternalHandle handle, int units, int percentage, long estimate) {
138
    public void explicitSelection(InternalHandle handle, int units, int percentage, long estimate) {
132
--
Line 143 Link Here
143
    void displayNameChange(InternalHandle handle, int units, int percentage, long estimate, String display) {
150
    public void displayNameChange(InternalHandle handle, int units, int percentage, long estimate, String display) {
144
--
(-)progress/src/org/netbeans/progress/module/InternalHandle.java (-344 lines)
Lines 1-344 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.module;
22
23
import java.awt.event.ActionEvent;
24
import java.util.ArrayList;
25
import java.util.Collection;
26
import java.util.Collections;
27
import java.util.List;
28
import java.util.logging.Level;
29
import java.util.logging.Logger;
30
import javax.swing.Action;
31
import javax.swing.JComponent;
32
import javax.swing.JProgressBar;
33
import javax.swing.SwingUtilities;
34
import org.netbeans.progress.module.ui.NbProgressBar;
35
import org.openide.util.Cancellable;
36
37
/**
38
 * Instances provided by the ProgressHandleFactory allow the users of the API to
39
 * notify the progress bar UI about changes in the state of the running task.
40
 * @author Milos Kleint (mkleint@netbeans.org)
41
 */
42
public final class InternalHandle {
43
    
44
    private String displayName;
45
    private boolean allowCancel;
46
    private boolean allowBackground;
47
    private boolean customPlaced = false;
48
    private int state;
49
    private int totalUnits;
50
    private int currentUnit;
51
    private long initialEstimate;
52
    private long timeStarted;
53
    private long timeLastProgress;
54
    private String lastMessage;
55
    private final Cancellable cancelable;
56
    private final Action viewAction;
57
    private final boolean userInitiated;
58
    private int initialDelay = Controller.INITIAL_DELAY;
59
    private Controller controller;
60
    
61
    public static final int STATE_INITIALIZED = 0;
62
    public static final int STATE_RUNNING = 1;
63
    public static final int STATE_FINISHED = 2;
64
    public static final int STATE_REQUEST_STOP = 3;
65
66
    public static final int NO_INCREASE = -2;
67
    
68
69
    
70
    /** Creates a new instance of ProgressHandle */
71
    public InternalHandle(String displayName, 
72
                   Cancellable cancel,
73
                   boolean userInitiated,
74
                   Action view) {
75
        this.displayName = displayName;
76
        this.userInitiated = userInitiated;
77
        state = STATE_INITIALIZED;
78
        totalUnits = 0;
79
        lastMessage = null;
80
        cancelable = cancel;
81
        viewAction = view;
82
    }
83
84
    public String getDisplayName() {
85
        return displayName;
86
    }
87
88
    /**
89
     * XXX - called from UI, threading
90
     */
91
    public synchronized int getState() {
92
        return state;
93
    }
94
    
95
    public boolean isAllowCancel() {
96
        return cancelable != null && !isCustomPlaced();
97
    }
98
    
99
    public boolean isAllowView() {
100
        return viewAction != null && !isCustomPlaced();
101
    }
102
    
103
    
104
    public boolean isCustomPlaced() {
105
        return customPlaced;
106
    }
107
    
108
    public boolean isUserInitialized() {
109
        return userInitiated;
110
    }
111
    
112
    private int getCurrentUnit() {
113
        return currentUnit;
114
    }
115
    
116
    public int getTotalUnits() {
117
        return totalUnits;
118
    }
119
    
120
    public void setInitialDelay(int millis) {
121
        if (state != STATE_INITIALIZED) {
122
            Logger.getAnonymousLogger().warning("Setting ProgressHandle.setInitialDelay() after the task is started has no effect"); //NOI18N
123
            return;
124
        }
125
        initialDelay = millis;
126
    }
127
    
128
    public int getInitialDelay() {
129
        return initialDelay;
130
    }
131
    
132
    public synchronized void toIndeterminate() {
133
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
134
            assert false : "cannot switch to indeterminate mode when not running";
135
        }
136
        totalUnits = 0;
137
        currentUnit = 0;
138
        initialEstimate = -1;
139
        timeLastProgress = System.currentTimeMillis();
140
        controller.toIndeterminate(this);
141
    }
142
    
143
    public synchronized void toDeterminate(int workunits, long estimate) {
144
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
145
            assert false : "cannot switch to determinate mode when not running";
146
        }
147
        if (workunits < 0) {
148
            throw new IllegalArgumentException("number of workunits cannot be negative");
149
        }        
150
        totalUnits = workunits;
151
        currentUnit = 0;
152
        initialEstimate = estimate;
153
        timeLastProgress = System.currentTimeMillis();
154
        controller.toDeterminate(this);
155
    }
156
    
157
    /**
158
     * start the progress indication for a task with known number of steps and known
159
     * time estimate for completing the task.
160
     * 
161
     * @param message 
162
     * @param workunits 
163
     * @param estimate estimated time to process the task in seconds
164
     */
165
    public synchronized void start(String message, int workunits, long estimate) {
166
        if (state != STATE_INITIALIZED) {
167
            throw new IllegalStateException("Cannot call start twice on a handle");
168
        }
169
        if (workunits < 0) {
170
            throw new IllegalArgumentException("number of workunits cannot be negative");
171
        }
172
        totalUnits = workunits;
173
        currentUnit = 0;
174
        if (message != null) {
175
            lastMessage = message;
176
        }
177
        state = STATE_RUNNING;
178
        initialEstimate = estimate;
179
        timeStarted = System.currentTimeMillis();
180
        timeLastProgress = timeStarted;
181
182
        if (! customPlaced) {
183
            controller = Controller.getDefault();
184
        }
185
        
186
        controller.start(this);
187
    }
188
189
    /**
190
     * finish the task, remove the task's component from the progress bar UI.
191
     */
192
    public synchronized void finish() {
193
        if (state == STATE_INITIALIZED) {
194
            throw new IllegalStateException("Cannot finish not a started task");
195
        }
196
        if (state == STATE_FINISHED) {
197
            return;
198
        }
199
        state = STATE_FINISHED;
200
        currentUnit = totalUnits;
201
        
202
        controller.finish(this);
203
    }
204
    
205
    
206
    /**
207
     * 
208
     * @param message 
209
     * @param workunit 
210
     */
211
    public synchronized void progress(String message, int workunit) {
212
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
213
            return;
214
        }
215
216
        if (workunit != NO_INCREASE) {
217
            if (workunit < currentUnit) {
218
                throw new IllegalArgumentException("Cannot decrease processed workunit count to lower value than before");
219
            }
220
            if (workunit > totalUnits) {
221
                // seems to be the by far most frequently abused contract. Record it to log file and safely handle the case
222
                Logger.getAnonymousLogger().log(Level.WARNING,
223
                    "Cannot process more work than scheduled. " +
224
                    "Progress handle with name \"" + getDisplayName() + "\" has requested progress to workunit no." + workunit + 
225
                    " but the total number of workunits is " + totalUnits + ". That means the progress bar UI will not display real progress and will stay at 100%.",
226
                    new IllegalArgumentException()
227
                );
228
                workunit = totalUnits;
229
            }
230
            currentUnit = workunit;
231
        }
232
        if (message != null) {
233
            lastMessage = message;
234
        }
235
        timeLastProgress = System.currentTimeMillis();
236
        
237
        controller.progress(this, message, currentUnit, 
238
                            totalUnits > 0 ? getPercentageDone() : -1, 
239
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
240
    }
241
    
242
    
243
  // XXX - called from UI, threading
244
245
    public void requestCancel() {
246
        if (!isAllowCancel()) {
247
            return;
248
        }
249
        synchronized (this) {
250
            state = STATE_REQUEST_STOP;
251
        }
252
        // do not call in synchronized block because it can take a long time to process, 
253
        ///  and it could slow down UI.
254
        //TODO - call in some other thread, not AWT? what is the cancel() contract?
255
        cancelable.cancel();
256
        synchronized (this) {
257
            requestStateSnapshot();
258
        }
259
    }
260
    
261
   ///XXX - called from UI, threading
262
    public void requestView() {
263
        if (!isAllowView()) {
264
            return;
265
        }
266
        viewAction.actionPerformed(new ActionEvent(viewAction, ActionEvent.ACTION_PERFORMED, "performView"));
267
    }
268
    
269
   // XXX - called from UI, threading
270
    public synchronized void requestExplicitSelection() {
271
        timeLastProgress = System.currentTimeMillis();
272
        controller.explicitSelection(this, currentUnit, 
273
                            totalUnits > 0 ? getPercentageDone() : -1, 
274
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
275
    }
276
    
277
    public synchronized void requestDisplayNameChange(String newDisplayName) {
278
        displayName = newDisplayName;
279
        if (state == STATE_INITIALIZED) {
280
            return;
281
        }
282
        timeLastProgress = System.currentTimeMillis();
283
        controller.displayNameChange(this, currentUnit, 
284
                            totalUnits > 0 ? getPercentageDone() : -1, 
285
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()), newDisplayName);
286
    }
287
    
288
// XXX - called from UI, threading 
289
    public synchronized ProgressEvent requestStateSnapshot() {
290
        timeLastProgress = System.currentTimeMillis();
291
        return controller.snapshot(this, lastMessage, currentUnit, 
292
                            totalUnits > 0 ? getPercentageDone() : -1, 
293
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
294
    }
295
    
296
    /**
297
     * have the component in custom location, don't include in the status bar.
298
     */
299
    public synchronized JComponent extractComponent() {
300
        if (customPlaced) {
301
            throw new IllegalStateException("Cannot retrieve progress component multiple times");
302
        }
303
        if (state != STATE_INITIALIZED) {
304
            throw new IllegalStateException("You can request custom placement of progress component only before starting the task");
305
        }
306
        customPlaced = true;
307
        ProgressUIWorker comp = new NbProgressBar();
308
        controller = new Controller(comp);
309
        return (JComponent)comp;
310
    }
311
    
312
    
313
    long calculateFinishEstimate() {
314
        
315
        // we are interested in seconds only
316
        double durationSoFar = ((double)(System.currentTimeMillis() - timeStarted)) / 1000;
317
        if (initialEstimate == -1) {
318
            // we don't have an initial estimate, calculate by real-life data only
319
            return (long)(durationSoFar *  (totalUnits - currentUnit) / totalUnits);
320
        } else {
321
            // in the begining give the initial estimate more weight than in the end.
322
            // should give us more smooth estimates 
323
            long remainingUnits = (totalUnits - currentUnit);
324
            double remainingPortion = (double)remainingUnits / (double)totalUnits;
325
            double currentEstimate = (double)durationSoFar / (double)currentUnit * totalUnits;
326
            long retValue = (long)(((initialEstimate * remainingUnits * remainingPortion) 
327
                         + (currentEstimate * remainingUnits * (1 - remainingPortion)))
328
                       / totalUnits); 
329
            return retValue;
330
        }
331
    }
332
    /**
333
     *public because of tests.
334
     */
335
    public int getPercentageDone() {
336
        return (int)((long)currentUnit * 100 / (long)totalUnits); 
337
    }
338
339
    long getTimeStampStarted() {
340
        return timeStarted;
341
    }
342
343
344
}
(-)progress/src/org/netbeans/progress/module/ProgressEvent.java (-126 lines)
Lines 1-126 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.module;
22
23
/**
24
 *
25
 * @author Milos Kleint (mkleint@netbeans.org)
26
 */
27
public final class ProgressEvent {
28
29
    public static final int TYPE_START = 0;
30
    public static final int TYPE_FINISH = 4;
31
    public static final int TYPE_REQUEST_STOP = 3;
32
    public static final int TYPE_PROGRESS = 1;
33
    public static final int TYPE_SWITCH = 5;
34
35
     private InternalHandle source;
36
     private long estimatedCompletion;
37
     private int percentageDone;
38
     private int workunitsDone;
39
     private String message;
40
     private int type;
41
     private boolean watched;
42
     private boolean switched;
43
     private String displayName;
44
    /** Creates a new instance of ProgressEvent 
45
     * @param type one of TYPE_START, TYPE_REQUEST_STOP, TYPE_FINISH, TYPE_SWITCHED
46
     */
47
    public ProgressEvent(InternalHandle src, int type, boolean isWatched) {
48
        source = src;
49
        estimatedCompletion = -1;
50
        percentageDone = -1;
51
        workunitsDone = -1;
52
        message = null;
53
        this.type = type;
54
        watched = isWatched;
55
        switched = (type == TYPE_SWITCH);
56
    }
57
    /**
58
     * @param percentage completed work percentage
59
     * @param estimate estimate of completion in seconds
60
     */
61
    public ProgressEvent(InternalHandle src, String msg, int units, int percentage, long estimate, boolean isWatched) {
62
        this(src, TYPE_PROGRESS, isWatched);
63
        workunitsDone = units;
64
        percentageDone = percentage;
65
        estimatedCompletion = estimate;
66
        message = msg;
67
    }
68
    public ProgressEvent(InternalHandle src, String msg, int units, int percentage, long estimate, boolean isWatched, String displayName) {
69
        this(src, msg, units, percentage, estimate, isWatched);
70
        this.displayName = displayName;
71
    }
72
    
73
    public InternalHandle getSource() {
74
        return source;
75
    }
76
77
    public long getEstimatedCompletion() {
78
        return estimatedCompletion;
79
    }
80
81
    public int getPercentageDone() {
82
        return percentageDone;
83
    }
84
85
    public int getWorkunitsDone() {
86
        return workunitsDone;
87
    }
88
89
    public String getMessage() {
90
        return message;
91
    }
92
93
    public int getType() {
94
        return type;
95
    }
96
    
97
    public boolean isWatched() {
98
        return watched;
99
    }
100
    
101
    /**
102
     * used in controller, preserve dynamic message from earlier events 
103
     * if this one doesn't have it's own.
104
     */
105
    void copyMessageFromEarlier(ProgressEvent last) {
106
        if (message == null) {
107
            message = last.getMessage();
108
        }
109
        if (displayName == null) {
110
            displayName = last.getDisplayName();
111
        }
112
    }
113
    
114
    void markAsSwitched() {
115
        switched = true;
116
    }
117
    
118
    public boolean isSwitched() {
119
        return switched;
120
    }
121
    
122
    public String getDisplayName() {
123
        return displayName;
124
    }
125
    
126
}
(-)progress/src/org/netbeans/progress/module/ProgressListAction.java (-4 / +2 lines)
Line 25 Link Here
25
import org.netbeans.progress.module.ui.StatusLineComponent;
25
import org.netbeans.progress.spi.ProgressUIWorkerWithModel;
26
--
Line 53 Link Here
53
        ((StatusLineComponent)Controller.getDefault().getVisualComponent()).showPopup();
53
        ((ProgressUIWorkerWithModel)Controller.getDefault().getVisualComponent()).showPopup();
54
--
(-)progress/src/org/netbeans/progress/module/ProgressUIWorker.java (-30 lines)
Lines 1-30 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.module;
21
22
/**
23
 *
24
 * @author mkleint
25
 */
26
public interface ProgressUIWorker {
27
28
    void processProgressEvent(ProgressEvent event);
29
    void processSelectedProgressEvent(ProgressEvent event);
30
}
(-)progress/src/org/netbeans/progress/module/TaskModel.java (-147 lines)
Lines 1-147 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.module;
22
23
import javax.swing.DefaultListModel;
24
import javax.swing.DefaultListSelectionModel;
25
import javax.swing.ListModel;
26
import javax.swing.ListSelectionModel;
27
import javax.swing.event.ListDataListener;
28
import javax.swing.event.ListSelectionListener;
29
30
/**
31
 *
32
 * @author Milos Kleint (mkleint@netbeans.org)
33
 */
34
public class TaskModel {
35
    private DefaultListSelectionModel selectionModel;
36
    private DefaultListModel model;
37
    private InternalHandle explicit;
38
    /** Creates a new instance of TaskModel */
39
    public TaskModel() {
40
        selectionModel = new DefaultListSelectionModel();
41
        model = new DefaultListModel();
42
    }
43
    
44
    
45
    
46
    public void addHandle(InternalHandle handle) {
47
        model.addElement(handle);
48
        if (handle.isUserInitialized() && explicit == null) {
49
            selectionModel.setSelectionInterval(model.size() - 1, model.size() - 1);
50
        }
51
    }
52
    
53
    public void removeHandle(InternalHandle handle) {
54
        if (explicit == handle) {
55
            explicit = null;
56
        }
57
        int index = model.indexOf(handle);
58
        if (selectionModel.getMinSelectionIndex() == index) {
59
            // if we are removing the handle that is selected, do tricks with selection
60
            // too figure out which one should be sleected now
61
            changeSelection(index);
62
        }
63
        InternalHandle selectedHandle = getSelectedHandle();
64
        model.removeElement(handle);
65
        if (selectedHandle != null) {
66
            selectionModel.setSelectionInterval(model.indexOf(selectedHandle), model.indexOf(selectedHandle));
67
        } else {
68
           //TODO what to do here? 
69
            selectionModel.clearSelection();
70
        }
71
        
72
    }
73
    
74
    /**
75
     * if we are removing the handle that is selected, do tricks with selection
76
     * too figure out which one should be sleected no     
77
     */
78
    private void changeSelection(int current) {
79
        InternalHandle last = null;
80
        for (int i = 0; i < model.size(); i++) {
81
            if (current != i) {
82
                InternalHandle handle = (InternalHandle)model.getElementAt(i);
83
                if (handle.isUserInitialized()) {
84
                    last = handle;
85
                } else if (last == null) {
86
                    last = handle;
87
                }
88
            }
89
        }
90
        if (last != null) {
91
            selectionModel.setSelectionInterval(model.indexOf(last), model.indexOf(last));
92
        } else {
93
            selectionModel.clearSelection();
94
        }
95
        
96
    }
97
    
98
    public void explicitlySelect(InternalHandle handle) {
99
        explicit = handle;
100
        int index = model.indexOf(explicit);
101
        if (index == -1) {
102
            //TODO what?
103
        }
104
        selectionModel.setSelectionInterval(index, index);
105
    }
106
    
107
    public InternalHandle getExplicitSelection() {
108
        return explicit;
109
    }
110
    
111
    public int getSize() {
112
        return model.size();
113
    }
114
           
115
    
116
    public InternalHandle[] getHandles() {
117
        InternalHandle[] handles = new InternalHandle[model.size()];
118
        model.copyInto(handles);
119
        return handles;
120
    }
121
    
122
    public InternalHandle getSelectedHandle() {
123
        int select = selectionModel.getMinSelectionIndex();
124
        if (select != -1) {
125
            if (select >= 0 && select < model.size()) {
126
                return (InternalHandle)model.getElementAt(selectionModel.getMinSelectionIndex());
127
            }
128
        }
129
        return null;
130
    }
131
    
132
    public void addListSelectionListener(ListSelectionListener listener) {
133
        selectionModel.addListSelectionListener(listener);
134
    }
135
    
136
    public void removeListSelectionListener(ListSelectionListener listener) {
137
        selectionModel.removeListSelectionListener(listener);
138
    }
139
    
140
    public void addListDataListener(ListDataListener listener) {
141
        model.addListDataListener(listener);
142
    }
143
    
144
    public void removeListDataListener(ListDataListener listener) {
145
        model.removeListDataListener(listener);
146
    }
147
}
(-)progress/src/org/netbeans/progress/module/resources/Bundle.properties (-2 / +1 lines)
Line 18 Link Here
18
OpenIDE-Module-Name=Progress API & UI
18
OpenIDE-Module-Name=Progress API
19
--
(-)progress/src/org/netbeans/progress/module/ui/Bundle.properties (-28 lines)
Lines 1-28 Link Here
1
# The contents of this file are subject to the terms of the Common Development
2
# and Distribution License (the License). You may not use this file except in
3
# compliance with the License.
4
#
5
# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
6
# or http://www.netbeans.org/cddl.txt.
7
#
8
# When distributing Covered Code, include this CDDL Header Notice in each file
9
# and include the License file at http://www.netbeans.org/cddl.txt.
10
# If applicable, add the following below the CDDL Header, with the fields
11
# enclosed by brackets [] replaced by your own identifying information:
12
# "Portions Copyrighted [year] [name of copyright owner]"
13
#
14
# The Original Software is NetBeans. The Initial Developer of the Original
15
# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
# Microsystems, Inc. All Rights Reserved.
17
18
NbProgressBar.tooltip1={0} tasks running. Click for details.
19
NbProgressBar.tooltip2={0} task running. Click for details.
20
ListComponent.btnClose.tooltip=Click to cancel process
21
ListComponent.bar.tooltip=Click to watch the process
22
Cancel_Question=Are you sure you want to cancel {0}?
23
Cancel_Question_Title=Cancel Running Task
24
StatusLineComponent.ShowProcessList=Show Processes
25
StatusLineComponent.Cancel=Cancel Process
26
StatusLineComponent.View=Show Output
27
ListComponent.Watch=Watch Process
28
(-)progress/src/org/netbeans/progress/module/ui/ListComponent.java (-390 lines)
Lines 1-390 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.module.ui;
21
22
import java.awt.Color;
23
import java.awt.Component;
24
import java.awt.Cursor;
25
import java.awt.Dimension;
26
import java.awt.Font;
27
import java.awt.Image;
28
import java.awt.LayoutManager;
29
import java.awt.event.ActionEvent;
30
import java.awt.event.FocusListener;
31
import java.awt.event.KeyEvent;
32
import java.awt.event.MouseAdapter;
33
import java.awt.event.MouseEvent;
34
import javax.swing.AbstractAction;
35
import javax.swing.Action;
36
import javax.swing.BorderFactory;
37
import javax.swing.Icon;
38
import javax.swing.ImageIcon;
39
import javax.swing.JButton;
40
import javax.swing.JLabel;
41
import javax.swing.JPanel;
42
import javax.swing.JPopupMenu;
43
import javax.swing.KeyStroke;
44
import javax.swing.UIManager;
45
import org.netbeans.progress.module.InternalHandle;
46
import org.netbeans.progress.module.ProgressEvent;
47
import org.openide.DialogDisplayer;
48
import org.openide.NotifyDescriptor;
49
import org.openide.util.NbBundle;
50
import org.openide.util.Utilities;
51
52
/**
53
 *
54
 * @author mkleint
55
 */
56
public class ListComponent extends JPanel {
57
    private NbProgressBar bar;
58
    private JLabel mainLabel;
59
    private JLabel dynaLabel;
60
    private JButton closeButton;
61
    private InternalHandle handle;
62
    private boolean watched;
63
    private Action cancelAction;
64
    private Color selectBgColor;
65
    private Color selectFgColor;
66
    private Color bgColor;
67
    private Color fgColor;
68
    private Color dynaFgColor;
69
    private int mainHeight;
70
    private int dynaHeight;
71
    
72
    /** Creates a new instance of ListComponent */
73
    public ListComponent(InternalHandle hndl) {
74
        setFocusable(true);
75
        setRequestFocusEnabled(true);
76
//        setVerifyInputWhenFocusTarget(false);
77
        mainLabel = new JLabel();
78
        dynaLabel = new JLabel();
79
        // in gtk, the panel is non-opague, meaning we cannot color background
80
        // #59419
81
        setOpaque(true);
82
        dynaLabel.setFont(dynaLabel.getFont().deriveFont((float) (dynaLabel.getFont().getSize() - 2)));
83
        bar = new NbProgressBar();        
84
        handle = hndl;
85
        Color bg = UIManager.getColor("nbProgressBar.popupText.background");
86
        if (bg != null) {
87
            setBackground(bg);
88
            mainLabel.setBackground(bg);
89
            dynaLabel.setBackground(bg);
90
        }
91
        bgColor = getBackground();
92
        Color dynaFg = UIManager.getColor("nbProgressBar.popupDynaText.foreground");
93
        if (dynaFg != null) {
94
            dynaLabel.setForeground(dynaFg);
95
        }
96
        dynaFgColor = dynaLabel.getForeground();
97
        fgColor = UIManager.getColor("nbProgressBar.popupText.foreground");
98
        if (fgColor != null) {
99
            mainLabel.setForeground(fgColor);
100
        }
101
        fgColor = mainLabel.getForeground();
102
        selectBgColor = UIManager.getColor("nbProgressBar.popupText.selectBackground");
103
        if (selectBgColor == null) {
104
            selectBgColor = UIManager.getColor("List.selectionBackground");
105
        }
106
        selectFgColor = UIManager.getColor("nbProgressBar.popupText.selectForeground");
107
        if (selectFgColor == null) {
108
            selectFgColor = UIManager.getColor("List.selectionForeground");
109
        }
110
        bar.setToolTipText(NbBundle.getMessage(ListComponent.class, "ListComponent.bar.tooltip"));
111
        bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
112
        //start figure out height
113
        mainLabel.setText("XYZ");
114
        dynaLabel.setText("XYZ");
115
        mainHeight = mainLabel.getPreferredSize().height;
116
        dynaHeight = dynaLabel.getPreferredSize().height;
117
        mainLabel.setText(null);
118
        dynaLabel.setText(null);
119
        //end figure out height
120
        
121
        setLayout(new CustomLayout());
122
        add(mainLabel);
123
        add(bar);
124
        MListener list = new MListener();
125
        if (handle.isAllowCancel()) {
126
            cancelAction = new CancelAction(false);
127
            closeButton = new JButton(cancelAction);
128
            closeButton.setBorderPainted(false);
129
            closeButton.setBorder(BorderFactory.createEmptyBorder());
130
            closeButton.setOpaque(false);
131
            
132
            closeButton.setToolTipText(NbBundle.getMessage(ListComponent.class, "ListComponent.btnClose.tooltip"));
133
            add(closeButton);
134
            if (handle.getState() != InternalHandle.STATE_RUNNING) {
135
                closeButton.setEnabled(false);
136
            }
137
        }
138
        add(dynaLabel);
139
        setBorder(BorderFactory.createEmptyBorder());
140
        addMouseListener(list);
141
        bar.addMouseListener(list);
142
        mainLabel.addMouseListener(list);
143
        dynaLabel.addMouseListener(list);
144
        if (handle.isAllowCancel()) {
145
            closeButton.addMouseListener(list);
146
        }
147
        
148
        mainLabel.setText(handle.getDisplayName());
149
        NbProgressBar.setupBar(handle, bar);
150
        addFocusListener(new FocusListener() {
151
            public void focusGained(java.awt.event.FocusEvent e) {
152
                if (!e.isTemporary()) {
153
                    setBackground(selectBgColor);
154
                    mainLabel.setBackground(selectBgColor);
155
                    dynaLabel.setBackground(selectBgColor);
156
                    mainLabel.setForeground(selectFgColor);
157
                    // TODO assuming now that dynalabel has always the same foreground color
158
                    // seems to be the case according to the spec
159
                    scrollRectToVisible(getBounds());
160
                }
161
            }
162
163
            public void focusLost(java.awt.event.FocusEvent e) {
164
                if (!e.isTemporary()) {
165
                    setBackground(bgColor);
166
                    mainLabel.setBackground(bgColor);
167
                    dynaLabel.setBackground(bgColor);
168
                    mainLabel.setForeground(fgColor);
169
                    // TODO assuming now that dynalabel has always the same foreground color
170
                    // seems to be the case according to the spec
171
                    
172
                }
173
            }
174
            
175
        });
176
        
177
    }
178
    
179
    
180
    Action getCancelAction() {
181
        return cancelAction;
182
    }
183
    
184
    InternalHandle getHandle() {
185
        return handle;
186
    }
187
    
188
    void processProgressEvent(ProgressEvent event) {
189
        if (event.getType() == ProgressEvent.TYPE_PROGRESS || 
190
                event.getType() == ProgressEvent.TYPE_SWITCH) {
191
            if (event.getSource() != handle) {
192
                throw new IllegalStateException();
193
            }
194
            if (event.isSwitched()) {
195
                NbProgressBar.setupBar(event.getSource(), bar);
196
            }
197
            if (event.getWorkunitsDone() > 0) {
198
                bar.setValue(event.getWorkunitsDone());
199
            }
200
            bar.setString(StatusLineComponent.getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
201
            if (event.getMessage() != null) {
202
                dynaLabel.setText(event.getMessage());
203
            }
204
            if (event.getSource().getState() == InternalHandle.STATE_REQUEST_STOP) {
205
                closeButton.setEnabled(false);
206
            }
207
            if (event.getDisplayName() != null) {
208
                mainLabel.setText(event.getDisplayName());
209
            }
210
        } else {
211
            throw new IllegalStateException();
212
        }
213
    }
214
215
    void markAsActive(boolean sel) {
216
        if (sel == watched) {
217
            return;
218
        }
219
        watched = sel;
220
        if (sel) {
221
            mainLabel.setFont(mainLabel.getFont().deriveFont(Font.BOLD));
222
        } else {
223
            mainLabel.setFont(mainLabel.getFont().deriveFont(Font.PLAIN));
224
        }
225
        if (mainLabel.isVisible()) {
226
            mainLabel.repaint();
227
        }
228
    }
229
    
230
    private class MListener extends MouseAdapter {
231
        public void mouseClicked(MouseEvent e) {
232
            if (e.getSource() == bar) {
233
                handle.requestExplicitSelection();
234
//                markAsSelected(true);
235
            }
236
            if (e.getClickCount() > 1 && (e.getSource() == mainLabel || e.getSource() == dynaLabel)) {
237
                handle.requestView();
238
            }
239
            if (e.getButton() != e.BUTTON1) {
240
                showMenu(e);
241
            } else {
242
                ListComponent.this.requestFocus();
243
            }
244
            
245
//            System.out.println("list component requesting focus..");
246
        }
247
    }
248
    
249
   private void showMenu(MouseEvent e) {
250
        JPopupMenu popup = new JPopupMenu();
251
        //mark teh popup for the status line awt listener
252
        popup.setName("progresspopup");
253
        popup.add(new ViewAction());
254
        popup.add(new WatchAction());
255
        popup.add(new CancelAction(true));
256
        popup.show((Component)e.getSource(), e.getX(), e.getY());
257
    }    
258
    
259
   private class CancelAction extends AbstractAction {
260
       CancelAction(boolean text) {
261
           if (text) {
262
               putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "StatusLineComponent.Cancel"));
263
               putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
264
           } else {
265
               Image icon = (Image)UIManager.get("nb.progress.cancel.icon");
266
               if (icon == null) {
267
                   // for custom L&F?
268
                   icon = Utilities.loadImage("org/netbeans/progress/module/resources/buton.png");
269
               }
270
               putValue(Action.SMALL_ICON, new ImageIcon(icon));
271
           }
272
            setEnabled(handle == null ? false : handle.isAllowCancel());
273
       }
274
275
        public void actionPerformed(ActionEvent actionEvent) {
276
            if (handle.getState() == InternalHandle.STATE_RUNNING) {
277
                String message = NbBundle.getMessage(ListComponent.class, "Cancel_Question", handle.getDisplayName());
278
                String title = NbBundle.getMessage(ListComponent.class, "Cancel_Question_Title");
279
                NotifyDescriptor dd = new NotifyDescriptor(message, title, 
280
                                           NotifyDescriptor.YES_NO_OPTION,
281
                                           NotifyDescriptor.QUESTION_MESSAGE, null, null);
282
                Object retType = DialogDisplayer.getDefault().notify(dd);
283
                if (retType == NotifyDescriptor.YES_OPTION) {
284
                    handle.requestCancel();
285
                }
286
            }
287
        }
288
    }
289
290
    private class ViewAction extends AbstractAction {
291
        public ViewAction() {
292
            putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "StatusLineComponent.View"));
293
            setEnabled(handle == null ? false : handle.isAllowView());
294
            putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
295
        }
296
        public void actionPerformed(ActionEvent actionEvent) {
297
            if (handle != null) {
298
                handle.requestView();
299
            }
300
        }
301
    }    
302
303
    private class WatchAction extends AbstractAction {
304
        public WatchAction() {
305
            putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "ListComponent.Watch"));
306
            putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0));
307
            setEnabled(true);
308
        }
309
        public void actionPerformed(ActionEvent actionEvent) {
310
            if (handle != null) {
311
                handle.requestExplicitSelection();
312
            }
313
        }
314
    }    
315
    
316
    
317
    private static final int UPPERMARGIN = 3;
318
    private static final int LEFTMARGIN = 2;
319
    private static final int BOTTOMMARGIN = 2;
320
    private static final int BETWEENTEXTMARGIN = 3;
321
    
322
    static final int ITEM_WIDTH = 400;
323
    
324
    private class CustomLayout implements LayoutManager {
325
        
326
        /**
327
         * If the layout manager uses a per-component string,
328
         * adds the component <code>comp</code> to the layout,
329
         * associating it 
330
         * with the string specified by <code>name</code>.
331
         * 
332
         * @param name the string to be associated with the component
333
         * @param comp the component to be added
334
         */
335
        public void addLayoutComponent(String name, java.awt.Component comp) {
336
        }
337
338
        /**
339
         * Calculates the preferred size dimensions for the specified 
340
         * container, given the components it contains.
341
         * @param parent the container to be laid out
342
         *  
343
         * @see #minimumLayoutSize
344
         */
345
        public Dimension preferredLayoutSize(java.awt.Container parent) {
346
            int height = UPPERMARGIN + mainHeight + BETWEENTEXTMARGIN + dynaHeight + BOTTOMMARGIN;
347
            return new Dimension(ITEM_WIDTH, height);
348
        }
349
350
        /**
351
         * 
352
         * Lays out the specified container.
353
         * @param parent the container to be laid out 
354
         */
355
        public void layoutContainer(java.awt.Container parent) {
356
            int parentWidth = parent.getWidth();
357
            int parentHeight = parent.getHeight();
358
            int offset = parentWidth - 18;
359
            if (closeButton != null) {
360
                closeButton.setBounds(offset, UPPERMARGIN, 18, mainHeight);            
361
            }
362
            // have the bar approx 30 percent of the width
363
            int barOffset = offset - (ITEM_WIDTH / 3);
364
            bar.setBounds(barOffset, UPPERMARGIN, offset - barOffset, mainHeight);
365
            mainLabel.setBounds(LEFTMARGIN, UPPERMARGIN, barOffset - LEFTMARGIN, mainHeight);
366
            dynaLabel.setBounds(LEFTMARGIN, mainHeight + UPPERMARGIN + BETWEENTEXTMARGIN, 
367
                                parentWidth - LEFTMARGIN, dynaHeight);
368
        }
369
370
        /**
371
         * 
372
         * Calculates the minimum size dimensions for the specified 
373
         * container, given the components it contains.
374
         * @param parent the component to be laid out
375
         * @see #preferredLayoutSize
376
         */
377
        public Dimension minimumLayoutSize(java.awt.Container parent) {
378
            return preferredLayoutSize(parent);
379
        }
380
381
        /**
382
         * Removes the specified component from the layout.
383
         * @param comp the component to be removed
384
         */
385
        public void removeLayoutComponent(java.awt.Component comp) {
386
        }
387
388
        
389
    }
390
}
(-)progress/src/org/netbeans/progress/module/ui/NbProgressBar.java (-116 lines)
Lines 1-116 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.module.ui;
21
22
import java.awt.Color;
23
import java.awt.Dimension;
24
import javax.swing.JProgressBar;
25
import javax.swing.UIManager;
26
import org.netbeans.progress.module.InternalHandle;
27
import org.netbeans.progress.module.ProgressUIWorker;
28
import org.netbeans.progress.module.ProgressEvent;
29
30
31
/**
32
 * progress component, let just put the UI related issues here, update the state from outside
33
34
 * @author mkleint
35
 */
36
public class NbProgressBar extends JProgressBar implements ProgressUIWorker {
37
    boolean isSetup = false;
38
    boolean usedInStatusBar = false;
39
    
40
    /** Creates a new instance of NbProgressBar */
41
    public NbProgressBar() {
42
        super();
43
        setOrientation(JProgressBar.HORIZONTAL);
44
        setAlignmentX(0.5f);
45
        setAlignmentY(0.5f);
46
        Color fg = UIManager.getColor ("nbProgressBar.Foreground");
47
        if (fg != null) {
48
            setForeground(fg);
49
        }
50
        Color bg = UIManager.getColor ("nbProgressBar.Background");
51
        if (bg != null) {
52
            setBackground(bg);
53
        }
54
    }
55
    
56
    public void setUseInStatusBar(boolean use) {
57
        usedInStatusBar = use;
58
    }
59
    
60
    public Dimension getPreferredSize() {
61
        Dimension supers = super.getPreferredSize();
62
        if (usedInStatusBar) {
63
            supers.width = ListComponent.ITEM_WIDTH / 3;
64
        }
65
        return supers;
66
    }
67
68
    
69
//--- these are used only when dealing with extracted component, when in status bar this is not used.    
70
//------------------------------------
71
    
72
    public void processProgressEvent(ProgressEvent event) {
73
        if (event.getType() == ProgressEvent.TYPE_START || !isSetup  || event.isSwitched()) {
74
            setupBar(event.getSource(), this);
75
            isSetup = true;
76
        } 
77
        if (event.getType() == ProgressEvent.TYPE_PROGRESS) {
78
            if (event.getWorkunitsDone() > 0) {
79
                setValue(event.getWorkunitsDone());
80
            }
81
            setString(StatusLineComponent.getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
82
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
83
            boolean wasIndetermenite = isIndeterminate();
84
            setIndeterminate(false);
85
            setMaximum(event.getSource().getTotalUnits());
86
            setValue(event.getSource().getTotalUnits());
87
            if (wasIndetermenite) {
88
                setStringPainted(false);
89
            } else {
90
                setString(StatusLineComponent.getBarString(100, -1));
91
            }
92
        }
93
    }
94
95
    public void processSelectedProgressEvent(ProgressEvent event) {
96
        // ignore we'return always processing just one selected component
97
    }
98
    
99
    
100
    static void setupBar(InternalHandle handle, NbProgressBar bar) {
101
        int total = handle.getTotalUnits();
102
        if (total < 1) {
103
            // macosx workaround..            
104
            bar.setValue(bar.getMaximum());
105
            bar.setIndeterminate(true);
106
            bar.setStringPainted(false);
107
        } else {
108
            bar.setStringPainted(true);
109
            bar.setIndeterminate(false);
110
            bar.setMaximum(total);
111
            bar.setMinimum(0);
112
            bar.setValue(0);
113
        }
114
        bar.setString(" ");
115
    }    
116
}
(-)progress/src/org/netbeans/progress/module/ui/PopupPane.java (-278 lines)
Lines 1-278 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.module.ui;
22
23
import java.awt.Color;
24
import java.awt.Component;
25
import java.awt.Dimension;
26
import java.awt.Graphics;
27
import java.awt.GridLayout;
28
import java.awt.Insets;
29
import java.awt.Toolkit;
30
import java.awt.event.ActionEvent;
31
import java.awt.event.KeyEvent;
32
import java.util.HashSet;
33
import java.util.Iterator;
34
import javax.swing.AbstractAction;
35
import javax.swing.Action;
36
import javax.swing.BorderFactory;
37
import javax.swing.JComponent;
38
import javax.swing.JPanel;
39
import javax.swing.JScrollPane;
40
import javax.swing.KeyStroke;
41
import javax.swing.UIManager;
42
import javax.swing.border.Border;
43
import org.netbeans.progress.module.InternalHandle;
44
45
/**
46
 *
47
 * @author mkleint
48
 */
49
public class PopupPane extends JScrollPane {
50
    private JPanel view;
51
    private HashSet<ListComponent> listComponents;
52
    /** Creates a new instance of PopupPane */
53
    private ListComponent selected;
54
    
55
    public PopupPane() {
56
        listComponents = new HashSet<ListComponent>();
57
        view = new JPanel();
58
        GridLayout grid = new GridLayout(0, 1);
59
        grid.setHgap(0);
60
        grid.setVgap(0);
61
        view.setLayout(grid);
62
        view.setBorder(BorderFactory.createEmptyBorder());
63
        setName("progresspopup"); //NOI18N
64
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
65
        setViewportView(view);
66
        setFocusable(true);
67
        setRequestFocusEnabled(true);
68
69
        Action down = new MoveDownAction();
70
        getActionMap().put("Move-Down", down);
71
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
72
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
73
        
74
        Action up = new MoveUpAction();
75
        getActionMap().put("Move-Up", up);
76
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
77
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
78
        Action cancel = new CancelAction();
79
        getActionMap().put("Cancel-Task", cancel);
80
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
81
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
82
        
83
        Action select = new SelectAction();
84
        getActionMap().put("select-task", select);
85
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
86
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
87
        
88
        
89
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
90
//        addFocusListener(new FocusListener() {
91
//            public void focusLost(java.awt.event.FocusEvent e) {
92
//                System.out.println("popup focus gained temp?=" + e.isTemporary());
93
//            }
94
//
95
//            public void focusGained(java.awt.event.FocusEvent e) {
96
//                System.out.println("popup focus lost temporary?=" + e.isTemporary());
97
//            }
98
//            
99
//        });
100
    }
101
    
102
    public void addListComponent(ListComponent lst) {
103
        listComponents.add(lst);
104
        if (view.getComponentCount() > 0) {
105
            JComponent previous = (JComponent)view.getComponent(view.getComponentCount() - 1);
106
            previous.setBorder(new BottomLineBorder());
107
        }
108
        lst.setBorder(BorderFactory.createEmptyBorder());
109
        view.add(lst);
110
        if (listComponents.size() > 3) {
111
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
112
        } else {
113
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
114
        }
115
    }
116
    
117
    public void removeListComponent(InternalHandle handle) {
118
        Iterator it = listComponents.iterator();
119
        while (it.hasNext()) {
120
            ListComponent comp = (ListComponent)it.next();
121
            if (comp.getHandle() == handle) {
122
                view.remove(comp);
123
                it.remove();
124
                break;
125
            }
126
        }
127
        if (listComponents.size() > 3) {
128
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
129
        } else {
130
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
131
        }
132
    }
133
134
    public Dimension getPreferredSize() {
135
        int count = view.getComponentCount();
136
        int height = count > 0 ? view.getComponent(0).getPreferredSize().height : 0;
137
        int offset = count > 3 ? height * 3 + 5 : (count * height) + 5;
138
        // 22 is the width of the additional scrollbar
139
        return new Dimension(count >3 ? ListComponent.ITEM_WIDTH + 22 
140
                                      : ListComponent.ITEM_WIDTH + 2, offset);
141
    }
142
143
    /**
144
     * bold font is now used not only for explicitly selected items, but for any 
145
     * change in currently selected task.
146
     */
147
    public void updateBoldFont(InternalHandle handle) {
148
        Iterator it = listComponents.iterator();
149
        while (it.hasNext()) {
150
            ListComponent comp = (ListComponent)it.next();
151
            comp.markAsActive(handle == comp.getHandle());
152
        }
153
    }
154
    
155
    
156
    
157
    private static class BottomLineBorder implements Border {
158
        private Insets ins = new Insets(0, 0, 1, 0);
159
        private Color col = new Color(221, 229, 248);
160
        
161
        public BottomLineBorder () {}
162
        
163
        public Insets getBorderInsets(Component c) {
164
            return ins;
165
        }
166
167
        public boolean isBorderOpaque() {
168
            return false;
169
        }
170
171
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
172
           Color old = g.getColor();
173
           g.setColor(col);
174
           g.drawRect(x, y + height - 2,  width, 1);
175
           g.setColor(old);
176
        }
177
    }
178
    
179
    private int findIndex(Component comp) {
180
        Component[] comps = view.getComponents();
181
        for (int i = 0; i < comps.length; i++) {
182
            if (comps[i] == comp) {
183
                return i;
184
            }
185
        }
186
        return -1;
187
    }
188
189
    public void requestFocus() {
190
//#63666 - don't focus any of the tasks explicitly, wait for user action.
191
//        if (view.getComponentCount() > 1) {
192
//            if (selected == null || !selected.isDisplayable()) {
193
//                selected = (ListComponent)view.getComponent(0);
194
//            }
195
//            selected.requestFocus();
196
//        } else {
197
            super.requestFocus();
198
//        }
199
    }
200
    
201
    private class MoveDownAction extends AbstractAction {
202
        
203
        MoveDownAction() {
204
        }
205
         
206
        public void actionPerformed(ActionEvent actionEvent) {
207
            int index = -1;
208
            if (selected != null) {
209
                index = findIndex(selected);
210
            }
211
            index = index + 1;
212
            if (index >= PopupPane.this.view.getComponentCount()) {
213
                index = 0;
214
            }
215
            selected = (ListComponent)PopupPane.this.view.getComponent(index);
216
            selected.requestFocus();
217
        }
218
        
219
    }
220
    
221
    private class MoveUpAction extends AbstractAction {
222
        
223
        MoveUpAction() {
224
        }
225
         
226
        public void actionPerformed(ActionEvent actionEvent) {
227
            int index = PopupPane.this.view.getComponentCount();
228
            if (selected != null) {
229
                index = findIndex(selected);
230
//                selected.setBackground(new Color(249, 249, 249));
231
            }
232
            index = index - 1;
233
            if (index < 0) {
234
                index = PopupPane.this.view.getComponentCount() - 1;
235
            }
236
            selected = (ListComponent)PopupPane.this.view.getComponent(index);
237
            selected.requestFocus();
238
//            selected.setBackground(selectBgColor);
239
//            selected.scrollRectToVisible(selected.getBounds());
240
        }
241
    }
242
    
243
    private class CancelAction extends AbstractAction {
244
        public CancelAction () {}
245
        
246
        public void actionPerformed(ActionEvent actionEvent) {
247
            if (selected != null) {
248
                Action act = selected.getCancelAction();
249
                if (act != null) {
250
                    act.actionPerformed(actionEvent);
251
                } else {
252
                    Toolkit.getDefaultToolkit().beep();
253
                }
254
            }
255
        }
256
    }
257
258
    private class SelectAction extends AbstractAction {
259
        public SelectAction () {}
260
        
261
        public void actionPerformed(ActionEvent actionEvent) {
262
            if (selected != null) {
263
                selected.getHandle().requestExplicitSelection();
264
            }
265
        }
266
    }
267
    
268
    private class ViewAction extends AbstractAction {
269
        public ViewAction () {}
270
        
271
        public void actionPerformed(ActionEvent actionEvent) {
272
            if (selected != null) {
273
                selected.getHandle().requestView();
274
            }
275
        }
276
    }
277
    
278
}
(-)progress/src/org/netbeans/progress/module/ui/StatusLineComponent.java (-464 lines)
Lines 1-464 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.module.ui;
22
import java.awt.AWTEvent;
23
import java.awt.Component;
24
import java.awt.Container;
25
import java.awt.Cursor;
26
import java.awt.Dimension;
27
import java.awt.FlowLayout;
28
import java.awt.Frame;
29
import java.awt.Point;
30
import java.awt.Rectangle;
31
import java.awt.Toolkit;
32
import java.awt.event.AWTEventListener;
33
import java.awt.event.ActionEvent;
34
import java.awt.event.ComponentAdapter;
35
import java.awt.event.ComponentEvent;
36
import java.awt.event.KeyEvent;
37
import java.awt.event.MouseAdapter;
38
import java.awt.event.MouseEvent;
39
import java.awt.event.MouseListener;
40
import java.awt.event.WindowEvent;
41
import java.awt.event.WindowStateListener;
42
import java.util.HashMap;
43
import java.util.Map;
44
import javax.swing.AbstractAction;
45
import javax.swing.Action;
46
import javax.swing.BorderFactory;
47
import javax.swing.JComponent;
48
import javax.swing.JLabel;
49
import javax.swing.JPanel;
50
import javax.swing.JPopupMenu;
51
import javax.swing.JSeparator;
52
import javax.swing.JWindow;
53
import javax.swing.KeyStroke;
54
import javax.swing.Popup;
55
import javax.swing.SwingUtilities;
56
import javax.swing.event.ListDataEvent;
57
import javax.swing.event.ListDataListener;
58
import javax.swing.event.ListSelectionEvent;
59
import javax.swing.event.ListSelectionListener;
60
import org.netbeans.progress.module.InternalHandle;
61
import org.netbeans.progress.module.ProgressUIWorker;
62
import org.netbeans.progress.module.ProgressEvent;
63
import org.netbeans.progress.module.ProgressListAction;
64
import org.netbeans.progress.module.TaskModel;
65
import org.openide.DialogDisplayer;
66
import org.openide.NotifyDescriptor;
67
import org.openide.util.NbBundle;
68
import org.openide.util.Utilities;
69
import org.openide.windows.WindowManager;
70
71
72
/**
73
 *
74
 * @author Milos Kleint (mkleint@netbeans.org)
75
 */
76
public class StatusLineComponent extends JPanel implements ProgressUIWorker {
77
    private NbProgressBar bar;
78
    private JLabel label;
79
    private JSeparator separator;
80
    private InternalHandle handle;
81
    private boolean showingPopup = false;
82
    private TaskModel model;
83
    private MouseListener mouseListener;
84
    private HideAWTListener hideListener;
85
    private Popup popup;
86
    private JWindow popupWindow;
87
    private PopupPane pane;
88
    private Map<InternalHandle, ListComponent> handleComponentMap;
89
    private final int prefferedHeight;
90
    /** Creates a new instance of StatusLineComponent */
91
    public StatusLineComponent() {
92
        handleComponentMap = new HashMap<InternalHandle, ListComponent>();
93
        label = new JLabel();
94
        label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
95
        bar = new NbProgressBar();
96
        bar.setUseInStatusBar(true);
97
        // tricks to figure out correct height.
98
        bar.setStringPainted(true);
99
        bar.setString("XXX");
100
        label.setText("XXX");
101
        prefferedHeight = Math.max(label.getPreferredSize().height, bar.getPreferredSize().height) + 2;
102
        
103
        bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
104
//        setBorder(BorderFactory.createLineBorder(Color.BLUE, 1));
105
        FlowLayout flay = new FlowLayout();
106
        flay.setVgap(1);
107
        flay.setHgap(5);
108
        setLayout(flay);
109
        // HACK - put smaller font inside the progress bar to keep
110
        // the height of the progressbar constant for determinate and indeterminate bars
111
//        Font fnt = UIManager.getFont("ProgressBar.font");
112
//        bar.setFont(fnt.deriveFont(fnt.getStyle(), fnt.getSize() - 3));
113
114
        mouseListener = new MListener();
115
        label.addMouseListener(mouseListener);
116
        bar.addMouseListener(mouseListener);
117
        addMouseListener(mouseListener);
118
        hideListener = new HideAWTListener();
119
        pane = new PopupPane();
120
        pane.getActionMap().put("HidePopup", new AbstractAction() {
121
            public void actionPerformed(ActionEvent actionEvent) {
122
//                System.out.println("escape pressed - hiding");
123
                hidePopup();
124
            }
125
        });
126
        pane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup");
127
        pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup");
128
        separator = new JSeparator(JSeparator.VERTICAL);
129
        separator.setPreferredSize(new Dimension(5, prefferedHeight));
130
        separator.setBorder(BorderFactory.createEmptyBorder(1, 0, 2, 0));
131
    }
132
    
133
    public Dimension getPreferredSize() {
134
        Dimension retValue;
135
        retValue = super.getPreferredSize();
136
        retValue.height = prefferedHeight;
137
        return retValue;
138
    }
139
140
    public Dimension getMinimumSize() {
141
        Dimension retValue;
142
        retValue = super.getMinimumSize();
143
        retValue.height = prefferedHeight;
144
        return retValue;
145
    }        
146
    
147
    public Dimension getMaximumSize() {
148
        Dimension retValue;
149
        retValue = super.getMaximumSize();
150
        retValue.height = prefferedHeight;
151
        return retValue;
152
    }        
153
    
154
    public void setModel(TaskModel mod) {
155
        model = mod;
156
        model.addListDataListener(new Listener());
157
        model.addListSelectionListener(new ListSelectionListener() {
158
            public void valueChanged(ListSelectionEvent e) {
159
                pane.updateBoldFont(model.getSelectedHandle());
160
            }
161
        });
162
    }
163
    
164
    private void setTooltipForAll() {
165
        int size = model.getSize();
166
        String key = "NbProgressBar.tooltip1"; //NOI18N
167
        if (size == 1) {
168
            key = "NbProgressBar.tooltip2"; //NOI18N
169
        }
170
        String text = NbBundle.getMessage(StatusLineComponent.class, key, new Integer(size));
171
        setToolTipText(text);
172
        label.setToolTipText(text);
173
        bar.setToolTipText(text);
174
    }
175
    
176
    public void processProgressEvent(ProgressEvent event) {
177
        if (event.getType() == ProgressEvent.TYPE_START) {
178
            createListItem(event.getSource());
179
        } else if (event.getType() == ProgressEvent.TYPE_PROGRESS || 
180
                   event.getType() == ProgressEvent.TYPE_SWITCH) {
181
            ListComponent comp = (ListComponent)handleComponentMap.get(event.getSource());
182
            if (comp == null) {
183
                createListItem(event.getSource());
184
                comp = (ListComponent)handleComponentMap.get(event.getSource());
185
            }
186
            comp.processProgressEvent(event);
187
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
188
            removeListItem(event.getSource());
189
            if (model.getSelectedHandle() != null && handle != model.getSelectedHandle()) {
190
                initiateComponent(model.getSelectedHandle().requestStateSnapshot());
191
            }
192
        }
193
        
194
    }
195
    
196
    public void processSelectedProgressEvent(ProgressEvent event) {
197
        if (event.getType() == ProgressEvent.TYPE_START) {
198
            initiateComponent(event);
199
            return;
200
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
201
            //happens only when there's no more handles.
202
            hidePopup();
203
            removeAll();
204
            //#63393, 61940 fix - removeAll() just invalidates. seems to work without revalidate/repaint on some platforms, fail on others.
205
            revalidate();
206
            repaint();
207
            return;
208
        } else {
209
            if (event.getSource() != handle || event.isSwitched()) {
210
                initiateComponent(event);
211
            }
212
            if (event.getWorkunitsDone() > 0) {
213
               bar.setValue(event.getWorkunitsDone());
214
            }
215
            bar.setString(getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
216
            if (event.getDisplayName() != null) {
217
                label.setText(event.getDisplayName());
218
            }
219
        } 
220
    }
221
    
222
    static String formatEstimate(long estimate) {
223
        long minutes = estimate / 60;
224
        long seconds = estimate - (minutes * 60);
225
        return "" + minutes + (seconds < 10 ? ":0" : ":") + seconds;
226
    }
227
    
228
    static String getBarString(int percentage, long estimatedCompletion) {
229
        if (estimatedCompletion != -1) {
230
            return formatEstimate(estimatedCompletion);
231
        }
232
        if (percentage != -1) {
233
            return "" + percentage + "%";
234
        }
235
        return "";
236
    }
237
    
238
    private void initiateComponent(ProgressEvent event) {
239
        handle = event.getSource();
240
        boolean toShow = false;
241
        label.setText(handle.getDisplayName());
242
        if (label.getParent() == null) {
243
            add(label);
244
            toShow = true;
245
        }
246
        NbProgressBar.setupBar(event.getSource(), bar);
247
        if (bar.getParent() == null) {
248
            add(bar);
249
            toShow = true;
250
        }
251
        if (separator.getParent() == null) {
252
            add(separator);
253
            toShow = true;
254
        }
255
        if (toShow) {
256
            revalidate();
257
            repaint();
258
        }
259
    }
260
    
261
    private class Listener implements ListDataListener {
262
        public void intervalAdded(ListDataEvent e) {
263
            setTooltipForAll();
264
        }
265
        
266
        public void intervalRemoved(ListDataEvent e) {
267
            setTooltipForAll();
268
        }
269
        
270
        
271
        public void contentsChanged(ListDataEvent e) {
272
            setTooltipForAll();
273
        }
274
    }
275
    
276
    public void hidePopup() {
277
        if (popupWindow != null) {
278
//            popupWindow.getContentPane().removeAll();
279
            popupWindow.setVisible(false);
280
        }
281
        Toolkit.getDefaultToolkit().removeAWTEventListener(hideListener);
282
        WindowManager.getDefault().getMainWindow().removeWindowStateListener(hideListener);
283
        WindowManager.getDefault().getMainWindow().removeComponentListener(hideListener);
284
        showingPopup = false;
285
    }
286
    
287
    private void createListItem(InternalHandle handle) {
288
        ListComponent comp;
289
        if (handleComponentMap.containsKey(handle)) {
290
            // happens when we click to display on popup and there is a 
291
            // new handle waiting in the queue.
292
            comp = handleComponentMap.get(handle);
293
        } else {
294
            comp = new ListComponent(handle);
295
            handleComponentMap.put(handle, comp);
296
        }
297
        pane.addListComponent(comp);            
298
        pane.updateBoldFont(model.getSelectedHandle());
299
        if (showingPopup) {
300
            resizePopup();
301
        }
302
    }
303
    
304
    private void removeListItem(InternalHandle handle) {
305
        handleComponentMap.remove(handle);
306
        pane.removeListComponent(handle);
307
        pane.updateBoldFont(model.getSelectedHandle());
308
        if (showingPopup) {
309
            resizePopup();
310
        }
311
    }
312
313
    
314
    public void showPopup() {
315
        if (showingPopup) {
316
            return;
317
        }
318
        InternalHandle[] handles = model.getHandles();
319
        if (handles.length == 0) {
320
            // just in case..
321
            return;
322
        }
323
        showingPopup = true;
324
        
325
        // NOT using PopupFactory
326
        // 1. on linux, creates mediumweight popup taht doesn't refresh behind visible glasspane
327
        // 2. on mac, needs an owner frame otherwise hiding tooltip also hides the popup. (linux requires no owner frame to force heavyweight)
328
        // 3. the created window is not focusable window
329
        if (popupWindow == null) {
330
            popupWindow = new JWindow(WindowManager.getDefault().getMainWindow());
331
            popupWindow.getContentPane().add(pane);
332
        }
333
        Toolkit.getDefaultToolkit().addAWTEventListener(hideListener, AWTEvent.MOUSE_EVENT_MASK);
334
        WindowManager.getDefault().getMainWindow().addWindowStateListener(hideListener);
335
        WindowManager.getDefault().getMainWindow().addComponentListener(hideListener);
336
        resizePopup();
337
        popupWindow.setVisible(true);
338
        pane.requestFocus();
339
//        System.out.println("     window focusable=" + popupWindow.isFocusableWindow());
340
    }
341
    
342
    private void resizePopup() {
343
        popupWindow.pack();
344
        Point point = new Point(0,0);
345
        SwingUtilities.convertPointToScreen(point, this);
346
        Dimension dim = popupWindow.getSize();
347
        //#63265 
348
        Rectangle usableRect = Utilities.getUsableScreenBounds();
349
        Point loc = new Point(point.x + this.getSize().width + 4 - dim.width , point.y - dim.height - 5);
350
        if (! usableRect.contains(loc)) {
351
            loc = new Point(loc.x, point.y + 5 + this.getSize().height);
352
        }
353
            // +4 here because of the width of the close button in popup, we
354
            // want the progress bars to align visually.. but there's separator in status now..
355
        popupWindow.setLocation(loc);
356
//        System.out.println("count=" + count);
357
//        System.out.println("offset =" + offset);
358
    }
359
    
360
    private class HideAWTListener extends ComponentAdapter implements  AWTEventListener, WindowStateListener {
361
        public void eventDispatched(java.awt.AWTEvent aWTEvent) {
362
            if (aWTEvent instanceof MouseEvent) {
363
                MouseEvent mv = (MouseEvent)aWTEvent;
364
                if (mv.getClickCount() > 0) {
365
                    Component comp = (Component)aWTEvent.getSource();
366
                    Container par = SwingUtilities.getAncestorNamed("progresspopup", comp); //NOI18N
367
                    Container barpar = SwingUtilities.getAncestorOfClass(StatusLineComponent.class, comp);
368
                    if (par == null && barpar == null) {
369
                        hidePopup();
370
                    }
371
                }
372
            }
373
        }
374
375
        public void windowStateChanged(WindowEvent windowEvent) {
376
            if (showingPopup) {
377
                int oldState = windowEvent.getOldState();
378
                int newState = windowEvent.getNewState();
379
            
380
                if (((oldState & Frame.ICONIFIED) == 0) &&
381
                    ((newState & Frame.ICONIFIED) == Frame.ICONIFIED)) {
382
                    hidePopup();
383
//                } else if (((oldState & Frame.ICONIFIED) == Frame.ICONIFIED) && 
384
//                           ((newState & Frame.ICONIFIED) == 0 )) {
385
//                    //TODO remember we showed before and show again? I guess not worth the efford, not part of spec.
386
                }
387
            }
388
389
        }
390
        
391
        public void componentResized(ComponentEvent evt) {
392
            if (showingPopup) {
393
                resizePopup();
394
            }
395
        }
396
        
397
        public void componentMoved(ComponentEvent evt) {
398
            if (showingPopup) {
399
                resizePopup();
400
            }
401
        }        
402
        
403
    }
404
    
405
    private class MListener extends MouseAdapter {
406
        public void mouseClicked(java.awt.event.MouseEvent e) {
407
            if (e.getButton() != MouseEvent.BUTTON1) {
408
                showMenu(e);
409
            } else {
410
                if (showingPopup) {
411
                    hidePopup();
412
                } else {
413
                    showPopup();
414
                }
415
            }
416
        }
417
        
418
    }
419
    
420
    private void showMenu(MouseEvent e) {
421
        JPopupMenu popup = new JPopupMenu();
422
        popup.add(new ProgressListAction(NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.ShowProcessList"))); 
423
        popup.add(new ViewAction());
424
        popup.add(new CancelAction());
425
        popup.show((Component)e.getSource(), e.getX(), e.getY());
426
    }
427
    
428
  private class CancelAction extends AbstractAction {
429
        public CancelAction() {
430
            putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.Cancel"));
431
            setEnabled(handle == null ? false : handle.isAllowCancel());
432
            
433
        }
434
        public void actionPerformed(ActionEvent actionEvent) {
435
            InternalHandle hndl = handle;
436
            if (hndl !=null && hndl.getState() == InternalHandle.STATE_RUNNING) {
437
                String message = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question", handle.getDisplayName());
438
                String title = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question_Title");
439
                NotifyDescriptor dd = new NotifyDescriptor(message, title, 
440
                                           NotifyDescriptor.YES_NO_OPTION,
441
                                           NotifyDescriptor.QUESTION_MESSAGE, null, null);
442
                Object retType = DialogDisplayer.getDefault().notify(dd);
443
                if (retType == NotifyDescriptor.YES_OPTION && hndl.getState() == InternalHandle.STATE_RUNNING) {
444
                    hndl.requestCancel();
445
                }
446
            }
447
        }
448
    }
449
450
    private class ViewAction extends AbstractAction {
451
        public ViewAction() {
452
            putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.View"));
453
            setEnabled(handle == null ? false : handle.isAllowView());
454
            
455
        }
456
        public void actionPerformed(ActionEvent actionEvent) {
457
            if (handle != null) {
458
                handle.requestView();
459
            }
460
        }
461
    }    
462
    
463
464
}
(-)progress/src/org/netbeans/progress/spi/InternalHandle.java (+347 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.spi;
22
23
import java.awt.event.ActionEvent;
24
import java.util.ArrayList;
25
import java.util.Collection;
26
import java.util.Collections;
27
import java.util.List;
28
import java.util.logging.Level;
29
import java.util.logging.Logger;
30
import javax.swing.Action;
31
import javax.swing.JComponent;
32
import javax.swing.JProgressBar;
33
import javax.swing.SwingUtilities;
34
import org.netbeans.progress.module.*;
35
import org.openide.util.Cancellable;
36
import org.openide.util.Lookup;
37
38
/**
39
 * Instances provided by the ProgressHandleFactory allow the users of the API to
40
 * notify the progress bar UI about changes in the state of the running task.
41
 * @author Milos Kleint (mkleint@netbeans.org)
42
 */
43
public final class InternalHandle {
44
    
45
    private String displayName;
46
    private boolean allowCancel;
47
    private boolean allowBackground;
48
    private boolean customPlaced = false;
49
    private int state;
50
    private int totalUnits;
51
    private int currentUnit;
52
    private long initialEstimate;
53
    private long timeStarted;
54
    private long timeLastProgress;
55
    private String lastMessage;
56
    private final Cancellable cancelable;
57
    private final Action viewAction;
58
    private final boolean userInitiated;
59
    private int initialDelay = Controller.INITIAL_DELAY;
60
    private Controller controller;
61
    
62
    public static final int STATE_INITIALIZED = 0;
63
    public static final int STATE_RUNNING = 1;
64
    public static final int STATE_FINISHED = 2;
65
    public static final int STATE_REQUEST_STOP = 3;
66
67
    public static final int NO_INCREASE = -2;
68
    
69
70
    
71
    /** Creates a new instance of ProgressHandle */
72
    public InternalHandle(String displayName, 
73
                   Cancellable cancel,
74
                   boolean userInitiated,
75
                   Action view) {
76
        this.displayName = displayName;
77
        this.userInitiated = userInitiated;
78
        state = STATE_INITIALIZED;
79
        totalUnits = 0;
80
        lastMessage = null;
81
        cancelable = cancel;
82
        viewAction = view;
83
    }
84
85
    public String getDisplayName() {
86
        return displayName;
87
    }
88
89
    /**
90
     * XXX - called from UI, threading
91
     */
92
    public synchronized int getState() {
93
        return state;
94
    }
95
    
96
    public boolean isAllowCancel() {
97
        return cancelable != null && !isCustomPlaced();
98
    }
99
    
100
    public boolean isAllowView() {
101
        return viewAction != null && !isCustomPlaced();
102
    }
103
    
104
    
105
    public boolean isCustomPlaced() {
106
        return customPlaced;
107
    }
108
    
109
    public boolean isUserInitialized() {
110
        return userInitiated;
111
    }
112
    
113
    private int getCurrentUnit() {
114
        return currentUnit;
115
    }
116
    
117
    public int getTotalUnits() {
118
        return totalUnits;
119
    }
120
    
121
    public void setInitialDelay(int millis) {
122
        if (state != STATE_INITIALIZED) {
123
            Logger.getAnonymousLogger().warning("Setting ProgressHandle.setInitialDelay() after the task is started has no effect"); //NOI18N
124
            return;
125
        }
126
        initialDelay = millis;
127
    }
128
    
129
    public int getInitialDelay() {
130
        return initialDelay;
131
    }
132
    
133
    public synchronized void toIndeterminate() {
134
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
135
            assert false : "cannot switch to indeterminate mode when not running";
136
        }
137
        totalUnits = 0;
138
        currentUnit = 0;
139
        initialEstimate = -1;
140
        timeLastProgress = System.currentTimeMillis();
141
        controller.toIndeterminate(this);
142
    }
143
    
144
    public synchronized void toDeterminate(int workunits, long estimate) {
145
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
146
            assert false : "cannot switch to determinate mode when not running";
147
        }
148
        if (workunits < 0) {
149
            throw new IllegalArgumentException("number of workunits cannot be negative");
150
        }        
151
        totalUnits = workunits;
152
        currentUnit = 0;
153
        initialEstimate = estimate;
154
        timeLastProgress = System.currentTimeMillis();
155
        controller.toDeterminate(this);
156
    }
157
    
158
    /**
159
     * start the progress indication for a task with known number of steps and known
160
     * time estimate for completing the task.
161
     * 
162
     * @param message 
163
     * @param workunits 
164
     * @param estimate estimated time to process the task in seconds
165
     */
166
    public synchronized void start(String message, int workunits, long estimate) {
167
        if (state != STATE_INITIALIZED) {
168
            throw new IllegalStateException("Cannot call start twice on a handle");
169
        }
170
        if (workunits < 0) {
171
            throw new IllegalArgumentException("number of workunits cannot be negative");
172
        }
173
        totalUnits = workunits;
174
        currentUnit = 0;
175
        if (message != null) {
176
            lastMessage = message;
177
        }
178
        state = STATE_RUNNING;
179
        initialEstimate = estimate;
180
        timeStarted = System.currentTimeMillis();
181
        timeLastProgress = timeStarted;
182
183
        if (! customPlaced) {
184
            controller = Controller.getDefault();
185
        }
186
        
187
        controller.start(this);
188
    }
189
190
    /**
191
     * finish the task, remove the task's component from the progress bar UI.
192
     */
193
    public synchronized void finish() {
194
        if (state == STATE_INITIALIZED) {
195
            throw new IllegalStateException("Cannot finish not a started task");
196
        }
197
        if (state == STATE_FINISHED) {
198
            return;
199
        }
200
        state = STATE_FINISHED;
201
        currentUnit = totalUnits;
202
        
203
        controller.finish(this);
204
    }
205
    
206
    
207
    /**
208
     * 
209
     * @param message 
210
     * @param workunit 
211
     */
212
    public synchronized void progress(String message, int workunit) {
213
        if (state != STATE_RUNNING && state != STATE_REQUEST_STOP) {
214
            return;
215
        }
216
217
        if (workunit != NO_INCREASE) {
218
            if (workunit < currentUnit) {
219
                throw new IllegalArgumentException("Cannot decrease processed workunit count to lower value than before");
220
            }
221
            if (workunit > totalUnits) {
222
                // seems to be the by far most frequently abused contract. Record it to log file and safely handle the case
223
                Logger.getAnonymousLogger().log(Level.WARNING,
224
                    "Cannot process more work than scheduled. " +
225
                    "Progress handle with name \"" + getDisplayName() + "\" has requested progress to workunit no." + workunit + 
226
                    " but the total number of workunits is " + totalUnits + ". That means the progress bar UI will not display real progress and will stay at 100%.",
227
                    new IllegalArgumentException()
228
                );
229
                workunit = totalUnits;
230
            }
231
            currentUnit = workunit;
232
        }
233
        if (message != null) {
234
            lastMessage = message;
235
        }
236
        timeLastProgress = System.currentTimeMillis();
237
        
238
        controller.progress(this, message, currentUnit, 
239
                            totalUnits > 0 ? getPercentageDone() : -1, 
240
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
241
    }
242
    
243
    
244
  // XXX - called from UI, threading
245
246
    public void requestCancel() {
247
        if (!isAllowCancel()) {
248
            return;
249
        }
250
        synchronized (this) {
251
            state = STATE_REQUEST_STOP;
252
        }
253
        // do not call in synchronized block because it can take a long time to process, 
254
        ///  and it could slow down UI.
255
        //TODO - call in some other thread, not AWT? what is the cancel() contract?
256
        cancelable.cancel();
257
        synchronized (this) {
258
            requestStateSnapshot();
259
        }
260
    }
261
    
262
   ///XXX - called from UI, threading
263
    public void requestView() {
264
        if (!isAllowView()) {
265
            return;
266
        }
267
        viewAction.actionPerformed(new ActionEvent(viewAction, ActionEvent.ACTION_PERFORMED, "performView"));
268
    }
269
    
270
   // XXX - called from UI, threading
271
    public synchronized void requestExplicitSelection() {
272
        timeLastProgress = System.currentTimeMillis();
273
        controller.explicitSelection(this, currentUnit, 
274
                            totalUnits > 0 ? getPercentageDone() : -1, 
275
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
276
    }
277
    
278
    public synchronized void requestDisplayNameChange(String newDisplayName) {
279
        displayName = newDisplayName;
280
        if (state == STATE_INITIALIZED) {
281
            return;
282
        }
283
        timeLastProgress = System.currentTimeMillis();
284
        controller.displayNameChange(this, currentUnit, 
285
                            totalUnits > 0 ? getPercentageDone() : -1, 
286
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()), newDisplayName);
287
    }
288
    
289
// XXX - called from UI, threading 
290
    public synchronized ProgressEvent requestStateSnapshot() {
291
        timeLastProgress = System.currentTimeMillis();
292
        return controller.snapshot(this, lastMessage, currentUnit, 
293
                            totalUnits > 0 ? getPercentageDone() : -1, 
294
                            (initialEstimate == -1 ? -1 : calculateFinishEstimate()));
295
    }
296
    
297
    /**
298
     * have the component in custom location, don't include in the status bar.
299
     */
300
    public synchronized JComponent extractComponent() {
301
        if (customPlaced) {
302
            throw new IllegalStateException("Cannot retrieve progress component multiple times");
303
        }
304
        if (state != STATE_INITIALIZED) {
305
            throw new IllegalStateException("You can request custom placement of progress component only before starting the task");
306
        }
307
        customPlaced = true;
308
        ProgressUIWorkerProvider prov = (ProgressUIWorkerProvider)Lookup.getDefault().lookup(ProgressUIWorkerProvider.class); 
309
        assert prov != null;
310
        ProgressUIWorker component = prov.getExtractedComponentWorker();
311
        controller = new Controller(component);
312
        return (JComponent)component;
313
    }
314
    
315
    
316
    long calculateFinishEstimate() {
317
        
318
        // we are interested in seconds only
319
        double durationSoFar = ((double)(System.currentTimeMillis() - timeStarted)) / 1000;
320
        if (initialEstimate == -1) {
321
            // we don't have an initial estimate, calculate by real-life data only
322
            return (long)(durationSoFar *  (totalUnits - currentUnit) / totalUnits);
323
        } else {
324
            // in the begining give the initial estimate more weight than in the end.
325
            // should give us more smooth estimates 
326
            long remainingUnits = (totalUnits - currentUnit);
327
            double remainingPortion = (double)remainingUnits / (double)totalUnits;
328
            double currentEstimate = (double)durationSoFar / (double)currentUnit * totalUnits;
329
            long retValue = (long)(((initialEstimate * remainingUnits * remainingPortion) 
330
                         + (currentEstimate * remainingUnits * (1 - remainingPortion)))
331
                       / totalUnits); 
332
            return retValue;
333
        }
334
    }
335
    /**
336
     *public because of tests.
337
     */
338
    public int getPercentageDone() {
339
        return (int)((long)currentUnit * 100 / (long)totalUnits); 
340
    }
341
342
    public long getTimeStampStarted() {
343
        return timeStarted;
344
    }
345
346
347
}
(-)progress/src/org/netbeans/progress/spi/ProgressEvent.java (+126 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.spi;
22
23
/**
24
 *
25
 * @author Milos Kleint (mkleint@netbeans.org)
26
 */
27
public final class ProgressEvent {
28
29
    public static final int TYPE_START = 0;
30
    public static final int TYPE_FINISH = 4;
31
    public static final int TYPE_REQUEST_STOP = 3;
32
    public static final int TYPE_PROGRESS = 1;
33
    public static final int TYPE_SWITCH = 5;
34
35
     private InternalHandle source;
36
     private long estimatedCompletion;
37
     private int percentageDone;
38
     private int workunitsDone;
39
     private String message;
40
     private int type;
41
     private boolean watched;
42
     private boolean switched;
43
     private String displayName;
44
    /** Creates a new instance of ProgressEvent 
45
     * @param type one of TYPE_START, TYPE_REQUEST_STOP, TYPE_FINISH, TYPE_SWITCHED
46
     */
47
    public ProgressEvent(InternalHandle src, int type, boolean isWatched) {
48
        source = src;
49
        estimatedCompletion = -1;
50
        percentageDone = -1;
51
        workunitsDone = -1;
52
        message = null;
53
        this.type = type;
54
        watched = isWatched;
55
        switched = (type == TYPE_SWITCH);
56
    }
57
    /**
58
     * @param percentage completed work percentage
59
     * @param estimate estimate of completion in seconds
60
     */
61
    public ProgressEvent(InternalHandle src, String msg, int units, int percentage, long estimate, boolean isWatched) {
62
        this(src, TYPE_PROGRESS, isWatched);
63
        workunitsDone = units;
64
        percentageDone = percentage;
65
        estimatedCompletion = estimate;
66
        message = msg;
67
    }
68
    public ProgressEvent(InternalHandle src, String msg, int units, int percentage, long estimate, boolean isWatched, String displayName) {
69
        this(src, msg, units, percentage, estimate, isWatched);
70
        this.displayName = displayName;
71
    }
72
    
73
    public InternalHandle getSource() {
74
        return source;
75
    }
76
77
    public long getEstimatedCompletion() {
78
        return estimatedCompletion;
79
    }
80
81
    public int getPercentageDone() {
82
        return percentageDone;
83
    }
84
85
    public int getWorkunitsDone() {
86
        return workunitsDone;
87
    }
88
89
    public String getMessage() {
90
        return message;
91
    }
92
93
    public int getType() {
94
        return type;
95
    }
96
    
97
    public boolean isWatched() {
98
        return watched;
99
    }
100
    
101
    /**
102
     * used in controller, preserve dynamic message from earlier events 
103
     * if this one doesn't have it's own.
104
     */
105
    public void copyMessageFromEarlier(ProgressEvent last) {
106
        if (message == null) {
107
            message = last.getMessage();
108
        }
109
        if (displayName == null) {
110
            displayName = last.getDisplayName();
111
        }
112
    }
113
    
114
    public void markAsSwitched() {
115
        switched = true;
116
    }
117
    
118
    public boolean isSwitched() {
119
        return switched;
120
    }
121
    
122
    public String getDisplayName() {
123
        return displayName;
124
    }
125
    
126
}
(-)progress/src/org/netbeans/progress/spi/ProgressUIWorker.java (+34 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.spi;
21
22
import org.netbeans.progress.module.*;
23
24
/**
25
 *
26
 * @author mkleint
27
 */
28
public interface ProgressUIWorker {
29
30
    void processProgressEvent(ProgressEvent event);
31
    void processSelectedProgressEvent(ProgressEvent event);
32
    
33
    
34
}
(-)progress/src/org/netbeans/progress/spi/ProgressUIWorkerProvider.java (+31 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.spi;
21
22
/**
23
 *
24
 * @author mkleint
25
 */
26
public interface ProgressUIWorkerProvider {
27
    
28
    public ProgressUIWorkerWithModel getDefaultWorker();
29
    
30
    public ProgressUIWorker getExtractedComponentWorker();
31
}
(-)progress/src/org/netbeans/progress/spi/ProgressUIWorkerWithModel.java (+33 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.progress.spi;
21
22
import org.netbeans.progress.module.*;
23
24
/**
25
 *
26
 * @author mkleint
27
 */
28
public interface ProgressUIWorkerWithModel extends ProgressUIWorker {
29
30
    void setModel(TaskModel model);
31
    
32
    void showPopup();
33
}
(-)progress/src/org/netbeans/progress/spi/TaskModel.java (+148 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.progress.spi;
22
23
import javax.swing.DefaultListModel;
24
import javax.swing.DefaultListSelectionModel;
25
import javax.swing.ListModel;
26
import javax.swing.ListSelectionModel;
27
import javax.swing.event.ListDataListener;
28
import javax.swing.event.ListSelectionListener;
29
import org.netbeans.progress.module.*;
30
31
/**
32
 *
33
 * @author Milos Kleint (mkleint@netbeans.org)
34
 */
35
public final class TaskModel {
36
    private DefaultListSelectionModel selectionModel;
37
    private DefaultListModel model;
38
    private InternalHandle explicit;
39
    /** Creates a new instance of TaskModel */
40
    public TaskModel() {
41
        selectionModel = new DefaultListSelectionModel();
42
        model = new DefaultListModel();
43
    }
44
    
45
    
46
    
47
    public void addHandle(InternalHandle handle) {
48
        model.addElement(handle);
49
        if (handle.isUserInitialized() && explicit == null) {
50
            selectionModel.setSelectionInterval(model.size() - 1, model.size() - 1);
51
        }
52
    }
53
    
54
    public void removeHandle(InternalHandle handle) {
55
        if (explicit == handle) {
56
            explicit = null;
57
        }
58
        int index = model.indexOf(handle);
59
        if (selectionModel.getMinSelectionIndex() == index) {
60
            // if we are removing the handle that is selected, do tricks with selection
61
            // too figure out which one should be sleected now
62
            changeSelection(index);
63
        }
64
        InternalHandle selectedHandle = getSelectedHandle();
65
        model.removeElement(handle);
66
        if (selectedHandle != null) {
67
            selectionModel.setSelectionInterval(model.indexOf(selectedHandle), model.indexOf(selectedHandle));
68
        } else {
69
           //TODO what to do here? 
70
            selectionModel.clearSelection();
71
        }
72
        
73
    }
74
    
75
    /**
76
     * if we are removing the handle that is selected, do tricks with selection
77
     * too figure out which one should be sleected no     
78
     */
79
    private void changeSelection(int current) {
80
        InternalHandle last = null;
81
        for (int i = 0; i < model.size(); i++) {
82
            if (current != i) {
83
                InternalHandle handle = (InternalHandle)model.getElementAt(i);
84
                if (handle.isUserInitialized()) {
85
                    last = handle;
86
                } else if (last == null) {
87
                    last = handle;
88
                }
89
            }
90
        }
91
        if (last != null) {
92
            selectionModel.setSelectionInterval(model.indexOf(last), model.indexOf(last));
93
        } else {
94
            selectionModel.clearSelection();
95
        }
96
        
97
    }
98
    
99
    public void explicitlySelect(InternalHandle handle) {
100
        explicit = handle;
101
        int index = model.indexOf(explicit);
102
        if (index == -1) {
103
            //TODO what?
104
        }
105
        selectionModel.setSelectionInterval(index, index);
106
    }
107
    
108
    public InternalHandle getExplicitSelection() {
109
        return explicit;
110
    }
111
    
112
    public int getSize() {
113
        return model.size();
114
    }
115
           
116
    
117
    public InternalHandle[] getHandles() {
118
        InternalHandle[] handles = new InternalHandle[model.size()];
119
        model.copyInto(handles);
120
        return handles;
121
    }
122
    
123
    public InternalHandle getSelectedHandle() {
124
        int select = selectionModel.getMinSelectionIndex();
125
        if (select != -1) {
126
            if (select >= 0 && select < model.size()) {
127
                return (InternalHandle)model.getElementAt(selectionModel.getMinSelectionIndex());
128
            }
129
        }
130
        return null;
131
    }
132
    
133
    public void addListSelectionListener(ListSelectionListener listener) {
134
        selectionModel.addListSelectionListener(listener);
135
    }
136
    
137
    public void removeListSelectionListener(ListSelectionListener listener) {
138
        selectionModel.removeListSelectionListener(listener);
139
    }
140
    
141
    public void addListDataListener(ListDataListener listener) {
142
        model.addListDataListener(listener);
143
    }
144
    
145
    public void removeListDataListener(ListDataListener listener) {
146
        model.removeListDataListener(listener);
147
    }
148
}
(-)progress/test/unit/src/org/netbeans/api/progress/ProgressHandleFactoryTest.java (-9 / +6 lines)
Line 23 Link Here
23
import javax.swing.JProgressBar;
Lines 24-25 Link Here
24
import org.netbeans.progress.module.InternalHandle;
25
import org.netbeans.progress.spi.InternalHandle;
25
import org.netbeans.progress.module.ui.NbProgressBar;
26
--
Lines 72-73 Link Here
72
        assertEquals(15, ((NbProgressBar) component).getMaximum());
72
        assertEquals(15, ((JProgressBar) component).getMaximum());
73
        assertEquals(2, ((NbProgressBar) component).getValue());
73
        assertEquals(2, ((JProgressBar) component).getValue());
74
--
Lines 85-86 Link Here
85
        assertEquals(20, ((NbProgressBar) component).getMaximum());
85
        assertEquals(20, ((JProgressBar) component).getMaximum());
86
        assertEquals(0, ((NbProgressBar) component).getValue());
86
        assertEquals(0, ((JProgressBar) component).getValue());
87
--
(-)progress/test/unit/src/org/netbeans/api/progress/ProgressHandleTest.java (-24 / +27 lines)
Line 22 Link Here
22
import java.lang.reflect.Method;
Lines 27-30 Link Here
27
import org.netbeans.progress.module.InternalHandle;
28
import org.netbeans.progress.spi.InternalHandle;
28
import org.netbeans.progress.module.ProgressUIWorker;
29
import org.netbeans.progress.spi.ProgressUIWorker;
29
import org.netbeans.progress.module.ProgressEvent;
30
import org.netbeans.progress.spi.ProgressEvent;
30
import org.netbeans.progress.module.ui.NbProgressBar;
31
--
Lines 309-322 Link Here
309
        
309
310
        class MyFrame extends JFrame implements Runnable {
310
class MyFrame extends JFrame implements Runnable {
311
            
311
    
312
            JComponent component;
312
    JComponent component;
313
            
313
    
314
            public MyFrame(JComponent component) {
314
    public MyFrame(JComponent component) {
315
                getContentPane().add(component);
315
        getContentPane().add(component);
316
            }
316
    }
317
            
317
    
318
            public void run() {
318
    public void run() {
319
                setVisible(true);
319
        setVisible(true);
320
                setBounds(0, 0, 400, 50);
320
        setBounds(0, 0, 400, 50);
321
            }
321
    }
322
        }
322
}
323
--
Lines 349-351 Link Here
349
        } 
349
        }
350
350
        try {
351
        assertFalse("The progress bar is still indeterminate!", ((NbProgressBar)component).isIndeterminate());
351
            Method meth = component.getClass().getMethod("isIndeterminate", new Class[0]);
352
--
352
            Boolean bool = (Boolean)meth.invoke(component, new Object[0]);
353
            assertFalse("The progress bar is still indeterminate!", bool.booleanValue());
354
        } catch (Exception ex) {
355
            ex.printStackTrace();
356
            fail();
357
        }
(-)progress/test/unit/src/org/netbeans/api/progress/aggregate/AggregateProgressHandleTest.java (-3 / +2 lines)
Lines 24-25 Link Here
24
import org.netbeans.progress.module.ProgressUIWorker;
24
import org.netbeans.progress.spi.ProgressUIWorker;
25
import org.netbeans.progress.module.ProgressEvent;
25
import org.netbeans.progress.spi.ProgressEvent;
26
--
(-)progressui/.cvsignore (+1 lines)
Line 1 Link Here
1
build
(-)progressui/build.xml (+5 lines)
Line 1 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="core/progress-ui">
3
    <description>Builds, tests, and runs the project org.netbeans.modules.progress.ui</description>
4
    <import file="../../nbbuild/templates/projectized.xml"/>
5
</project>
(-)progressui/manifest.mf (+7 lines)
Line 1 Link Here
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.progress.ui
3
OpenIDE-Module-Layer: org/netbeans/modules/progress/ui/layer.xml
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/progress/ui/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Provides: org.netbeans.spi.progress.ProgressUIWorkerProvider
7
(-)progressui/nbproject/project.properties (+4 lines)
Line 1 Link Here
1
# Sample ResourceBundle properties file
2
is.autoload=true
3
javac.compilerargs=-Xlint:unchecked
4
javac.source=1.5
(-)progressui/nbproject/project.xml (+45 lines)
Line 1 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/2">
6
            <code-name-base>org.netbeans.modules.progress.ui</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.netbeans.api.progress</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <release-version>1</release-version>
14
                        <implementation-version/>
15
                    </run-dependency>
16
                </dependency>
17
                <dependency>
18
                    <code-name-base>org.openide.dialogs</code-name-base>
19
                    <build-prerequisite/>
20
                    <compile-dependency/>
21
                    <run-dependency>
22
                        <specification-version>7.0</specification-version>
23
                    </run-dependency>
24
                </dependency>
25
                <dependency>
26
                    <code-name-base>org.openide.util</code-name-base>
27
                    <build-prerequisite/>
28
                    <compile-dependency/>
29
                    <run-dependency>
30
                        <specification-version>7.3</specification-version>
31
                    </run-dependency>
32
                </dependency>
33
                <dependency>
34
                    <code-name-base>org.openide.windows</code-name-base>
35
                    <build-prerequisite/>
36
                    <compile-dependency/>
37
                    <run-dependency>
38
                        <specification-version>6.7</specification-version>
39
                    </run-dependency>
40
                </dependency>
41
            </module-dependencies>
42
            <public-packages/>
43
        </data>
44
    </configuration>
45
</project>
(-)progressui/src/META-INF/services/org.netbeans.progress.spi.ProgressUIWorkerProvider (+1 lines)
Line 1 Link Here
1
org.netbeans.modules.progress.ui.ProviderImpl
(-)progressui/src/org/netbeans/modules/progress/ui/Bundle.properties (+28 lines)
Line 1 Link Here
1
# The contents of this file are subject to the terms of the Common Development
2
# and Distribution License (the License). You may not use this file except in
3
# compliance with the License.
4
#
5
# You can obtain a copy of the License at http://www.netbeans.org/cddl.html
6
# or http://www.netbeans.org/cddl.txt.
7
#
8
# When distributing Covered Code, include this CDDL Header Notice in each file
9
# and include the License file at http://www.netbeans.org/cddl.txt.
10
# If applicable, add the following below the CDDL Header, with the fields
11
# enclosed by brackets [] replaced by your own identifying information:
12
# "Portions Copyrighted [year] [name of copyright owner]"
13
#
14
# The Original Software is NetBeans. The Initial Developer of the Original
15
# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
# Microsystems, Inc. All Rights Reserved.
17
18
NbProgressBar.tooltip1={0} tasks running. Click for details.
19
NbProgressBar.tooltip2={0} task running. Click for details.
20
ListComponent.btnClose.tooltip=Click to cancel process
21
ListComponent.bar.tooltip=Click to watch the process
22
Cancel_Question=Are you sure you want to cancel {0}?
23
Cancel_Question_Title=Cancel Running Task
24
StatusLineComponent.ShowProcessList=Show Processes
25
StatusLineComponent.Cancel=Cancel Process
26
StatusLineComponent.View=Show Output
27
ListComponent.Watch=Watch Process
28
OpenIDE-Module-Name=Progress UI
(-)progressui/src/org/netbeans/modules/progress/ui/ListComponent.java (+390 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.progress.ui;
21
22
import java.awt.Color;
23
import java.awt.Component;
24
import java.awt.Cursor;
25
import java.awt.Dimension;
26
import java.awt.Font;
27
import java.awt.Image;
28
import java.awt.LayoutManager;
29
import java.awt.event.ActionEvent;
30
import java.awt.event.FocusListener;
31
import java.awt.event.KeyEvent;
32
import java.awt.event.MouseAdapter;
33
import java.awt.event.MouseEvent;
34
import javax.swing.AbstractAction;
35
import javax.swing.Action;
36
import javax.swing.BorderFactory;
37
import javax.swing.Icon;
38
import javax.swing.ImageIcon;
39
import javax.swing.JButton;
40
import javax.swing.JLabel;
41
import javax.swing.JPanel;
42
import javax.swing.JPopupMenu;
43
import javax.swing.KeyStroke;
44
import javax.swing.UIManager;
45
import org.netbeans.progress.spi.InternalHandle;
46
import org.netbeans.progress.spi.ProgressEvent;
47
import org.openide.DialogDisplayer;
48
import org.openide.NotifyDescriptor;
49
import org.openide.util.NbBundle;
50
import org.openide.util.Utilities;
51
52
/**
53
 *
54
 * @author mkleint
55
 */
56
public class ListComponent extends JPanel {
57
    private NbProgressBar bar;
58
    private JLabel mainLabel;
59
    private JLabel dynaLabel;
60
    private JButton closeButton;
61
    private InternalHandle handle;
62
    private boolean watched;
63
    private Action cancelAction;
64
    private Color selectBgColor;
65
    private Color selectFgColor;
66
    private Color bgColor;
67
    private Color fgColor;
68
    private Color dynaFgColor;
69
    private int mainHeight;
70
    private int dynaHeight;
71
    
72
    /** Creates a new instance of ListComponent */
73
    public ListComponent(InternalHandle hndl) {
74
        setFocusable(true);
75
        setRequestFocusEnabled(true);
76
//        setVerifyInputWhenFocusTarget(false);
77
        mainLabel = new JLabel();
78
        dynaLabel = new JLabel();
79
        // in gtk, the panel is non-opague, meaning we cannot color background
80
        // #59419
81
        setOpaque(true);
82
        dynaLabel.setFont(dynaLabel.getFont().deriveFont((float) (dynaLabel.getFont().getSize() - 2)));
83
        bar = new NbProgressBar();        
84
        handle = hndl;
85
        Color bg = UIManager.getColor("nbProgressBar.popupText.background");
86
        if (bg != null) {
87
            setBackground(bg);
88
            mainLabel.setBackground(bg);
89
            dynaLabel.setBackground(bg);
90
        }
91
        bgColor = getBackground();
92
        Color dynaFg = UIManager.getColor("nbProgressBar.popupDynaText.foreground");
93
        if (dynaFg != null) {
94
            dynaLabel.setForeground(dynaFg);
95
        }
96
        dynaFgColor = dynaLabel.getForeground();
97
        fgColor = UIManager.getColor("nbProgressBar.popupText.foreground");
98
        if (fgColor != null) {
99
            mainLabel.setForeground(fgColor);
100
        }
101
        fgColor = mainLabel.getForeground();
102
        selectBgColor = UIManager.getColor("nbProgressBar.popupText.selectBackground");
103
        if (selectBgColor == null) {
104
            selectBgColor = UIManager.getColor("List.selectionBackground");
105
        }
106
        selectFgColor = UIManager.getColor("nbProgressBar.popupText.selectForeground");
107
        if (selectFgColor == null) {
108
            selectFgColor = UIManager.getColor("List.selectionForeground");
109
        }
110
        bar.setToolTipText(NbBundle.getMessage(ListComponent.class, "ListComponent.bar.tooltip"));
111
        bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
112
        //start figure out height
113
        mainLabel.setText("XYZ");
114
        dynaLabel.setText("XYZ");
115
        mainHeight = mainLabel.getPreferredSize().height;
116
        dynaHeight = dynaLabel.getPreferredSize().height;
117
        mainLabel.setText(null);
118
        dynaLabel.setText(null);
119
        //end figure out height
120
        
121
        setLayout(new CustomLayout());
122
        add(mainLabel);
123
        add(bar);
124
        MListener list = new MListener();
125
        if (handle.isAllowCancel()) {
126
            cancelAction = new CancelAction(false);
127
            closeButton = new JButton(cancelAction);
128
            closeButton.setBorderPainted(false);
129
            closeButton.setBorder(BorderFactory.createEmptyBorder());
130
            closeButton.setOpaque(false);
131
            
132
            closeButton.setToolTipText(NbBundle.getMessage(ListComponent.class, "ListComponent.btnClose.tooltip"));
133
            add(closeButton);
134
            if (handle.getState() != InternalHandle.STATE_RUNNING) {
135
                closeButton.setEnabled(false);
136
            }
137
        }
138
        add(dynaLabel);
139
        setBorder(BorderFactory.createEmptyBorder());
140
        addMouseListener(list);
141
        bar.addMouseListener(list);
142
        mainLabel.addMouseListener(list);
143
        dynaLabel.addMouseListener(list);
144
        if (handle.isAllowCancel()) {
145
            closeButton.addMouseListener(list);
146
        }
147
        
148
        mainLabel.setText(handle.getDisplayName());
149
        NbProgressBar.setupBar(handle, bar);
150
        addFocusListener(new FocusListener() {
151
            public void focusGained(java.awt.event.FocusEvent e) {
152
                if (!e.isTemporary()) {
153
                    setBackground(selectBgColor);
154
                    mainLabel.setBackground(selectBgColor);
155
                    dynaLabel.setBackground(selectBgColor);
156
                    mainLabel.setForeground(selectFgColor);
157
                    // TODO assuming now that dynalabel has always the same foreground color
158
                    // seems to be the case according to the spec
159
                    scrollRectToVisible(getBounds());
160
                }
161
            }
162
163
            public void focusLost(java.awt.event.FocusEvent e) {
164
                if (!e.isTemporary()) {
165
                    setBackground(bgColor);
166
                    mainLabel.setBackground(bgColor);
167
                    dynaLabel.setBackground(bgColor);
168
                    mainLabel.setForeground(fgColor);
169
                    // TODO assuming now that dynalabel has always the same foreground color
170
                    // seems to be the case according to the spec
171
                    
172
                }
173
            }
174
            
175
        });
176
        
177
    }
178
    
179
    
180
    Action getCancelAction() {
181
        return cancelAction;
182
    }
183
    
184
    InternalHandle getHandle() {
185
        return handle;
186
    }
187
    
188
    void processProgressEvent(ProgressEvent event) {
189
        if (event.getType() == ProgressEvent.TYPE_PROGRESS || 
190
                event.getType() == ProgressEvent.TYPE_SWITCH) {
191
            if (event.getSource() != handle) {
192
                throw new IllegalStateException();
193
            }
194
            if (event.isSwitched()) {
195
                NbProgressBar.setupBar(event.getSource(), bar);
196
            }
197
            if (event.getWorkunitsDone() > 0) {
198
                bar.setValue(event.getWorkunitsDone());
199
            }
200
            bar.setString(StatusLineComponent.getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
201
            if (event.getMessage() != null) {
202
                dynaLabel.setText(event.getMessage());
203
            }
204
            if (event.getSource().getState() == InternalHandle.STATE_REQUEST_STOP) {
205
                closeButton.setEnabled(false);
206
            }
207
            if (event.getDisplayName() != null) {
208
                mainLabel.setText(event.getDisplayName());
209
            }
210
        } else {
211
            throw new IllegalStateException();
212
        }
213
    }
214
215
    void markAsActive(boolean sel) {
216
        if (sel == watched) {
217
            return;
218
        }
219
        watched = sel;
220
        if (sel) {
221
            mainLabel.setFont(mainLabel.getFont().deriveFont(Font.BOLD));
222
        } else {
223
            mainLabel.setFont(mainLabel.getFont().deriveFont(Font.PLAIN));
224
        }
225
        if (mainLabel.isVisible()) {
226
            mainLabel.repaint();
227
        }
228
    }
229
    
230
    private class MListener extends MouseAdapter {
231
        public void mouseClicked(MouseEvent e) {
232
            if (e.getSource() == bar) {
233
                handle.requestExplicitSelection();
234
//                markAsSelected(true);
235
            }
236
            if (e.getClickCount() > 1 && (e.getSource() == mainLabel || e.getSource() == dynaLabel)) {
237
                handle.requestView();
238
            }
239
            if (e.getButton() != e.BUTTON1) {
240
                showMenu(e);
241
            } else {
242
                ListComponent.this.requestFocus();
243
            }
244
            
245
//            System.out.println("list component requesting focus..");
246
        }
247
    }
248
    
249
   private void showMenu(MouseEvent e) {
250
        JPopupMenu popup = new JPopupMenu();
251
        //mark teh popup for the status line awt listener
252
        popup.setName("progresspopup");
253
        popup.add(new ViewAction());
254
        popup.add(new WatchAction());
255
        popup.add(new CancelAction(true));
256
        popup.show((Component)e.getSource(), e.getX(), e.getY());
257
    }    
258
    
259
   private class CancelAction extends AbstractAction {
260
       CancelAction(boolean text) {
261
           if (text) {
262
               putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "StatusLineComponent.Cancel"));
263
               putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
264
           } else {
265
               Image icon = (Image)UIManager.get("nb.progress.cancel.icon");
266
               if (icon == null) {
267
                   // for custom L&F?
268
                   icon = Utilities.loadImage("org/netbeans/progress/module/resources/buton.png");
269
               }
270
               putValue(Action.SMALL_ICON, new ImageIcon(icon));
271
           }
272
            setEnabled(handle == null ? false : handle.isAllowCancel());
273
       }
274
275
        public void actionPerformed(ActionEvent actionEvent) {
276
            if (handle.getState() == InternalHandle.STATE_RUNNING) {
277
                String message = NbBundle.getMessage(ListComponent.class, "Cancel_Question", handle.getDisplayName());
278
                String title = NbBundle.getMessage(ListComponent.class, "Cancel_Question_Title");
279
                NotifyDescriptor dd = new NotifyDescriptor(message, title, 
280
                                           NotifyDescriptor.YES_NO_OPTION,
281
                                           NotifyDescriptor.QUESTION_MESSAGE, null, null);
282
                Object retType = DialogDisplayer.getDefault().notify(dd);
283
                if (retType == NotifyDescriptor.YES_OPTION) {
284
                    handle.requestCancel();
285
                }
286
            }
287
        }
288
    }
289
290
    private class ViewAction extends AbstractAction {
291
        public ViewAction() {
292
            putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "StatusLineComponent.View"));
293
            setEnabled(handle == null ? false : handle.isAllowView());
294
            putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
295
        }
296
        public void actionPerformed(ActionEvent actionEvent) {
297
            if (handle != null) {
298
                handle.requestView();
299
            }
300
        }
301
    }    
302
303
    private class WatchAction extends AbstractAction {
304
        public WatchAction() {
305
            putValue(Action.NAME, NbBundle.getMessage(ListComponent.class, "ListComponent.Watch"));
306
            putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0));
307
            setEnabled(true);
308
        }
309
        public void actionPerformed(ActionEvent actionEvent) {
310
            if (handle != null) {
311
                handle.requestExplicitSelection();
312
            }
313
        }
314
    }    
315
    
316
    
317
    private static final int UPPERMARGIN = 3;
318
    private static final int LEFTMARGIN = 2;
319
    private static final int BOTTOMMARGIN = 2;
320
    private static final int BETWEENTEXTMARGIN = 3;
321
    
322
    static final int ITEM_WIDTH = 400;
323
    
324
    private class CustomLayout implements LayoutManager {
325
        
326
        /**
327
         * If the layout manager uses a per-component string,
328
         * adds the component <code>comp</code> to the layout,
329
         * associating it 
330
         * with the string specified by <code>name</code>.
331
         * 
332
         * @param name the string to be associated with the component
333
         * @param comp the component to be added
334
         */
335
        public void addLayoutComponent(String name, java.awt.Component comp) {
336
        }
337
338
        /**
339
         * Calculates the preferred size dimensions for the specified 
340
         * container, given the components it contains.
341
         * @param parent the container to be laid out
342
         *  
343
         * @see #minimumLayoutSize
344
         */
345
        public Dimension preferredLayoutSize(java.awt.Container parent) {
346
            int height = UPPERMARGIN + mainHeight + BETWEENTEXTMARGIN + dynaHeight + BOTTOMMARGIN;
347
            return new Dimension(ITEM_WIDTH, height);
348
        }
349
350
        /**
351
         * 
352
         * Lays out the specified container.
353
         * @param parent the container to be laid out 
354
         */
355
        public void layoutContainer(java.awt.Container parent) {
356
            int parentWidth = parent.getWidth();
357
            int parentHeight = parent.getHeight();
358
            int offset = parentWidth - 18;
359
            if (closeButton != null) {
360
                closeButton.setBounds(offset, UPPERMARGIN, 18, mainHeight);            
361
            }
362
            // have the bar approx 30 percent of the width
363
            int barOffset = offset - (ITEM_WIDTH / 3);
364
            bar.setBounds(barOffset, UPPERMARGIN, offset - barOffset, mainHeight);
365
            mainLabel.setBounds(LEFTMARGIN, UPPERMARGIN, barOffset - LEFTMARGIN, mainHeight);
366
            dynaLabel.setBounds(LEFTMARGIN, mainHeight + UPPERMARGIN + BETWEENTEXTMARGIN, 
367
                                parentWidth - LEFTMARGIN, dynaHeight);
368
        }
369
370
        /**
371
         * 
372
         * Calculates the minimum size dimensions for the specified 
373
         * container, given the components it contains.
374
         * @param parent the component to be laid out
375
         * @see #preferredLayoutSize
376
         */
377
        public Dimension minimumLayoutSize(java.awt.Container parent) {
378
            return preferredLayoutSize(parent);
379
        }
380
381
        /**
382
         * Removes the specified component from the layout.
383
         * @param comp the component to be removed
384
         */
385
        public void removeLayoutComponent(java.awt.Component comp) {
386
        }
387
388
        
389
    }
390
}
(-)progressui/src/org/netbeans/modules/progress/ui/NbProgressBar.java (+116 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.progress.ui;
21
22
import java.awt.Color;
23
import java.awt.Dimension;
24
import javax.swing.JProgressBar;
25
import javax.swing.UIManager;
26
import org.netbeans.progress.spi.InternalHandle;
27
import org.netbeans.progress.spi.ProgressUIWorker;
28
import org.netbeans.progress.spi.ProgressEvent;
29
30
31
/**
32
 * progress component, let just put the UI related issues here, update the state from outside
33
34
 * @author mkleint
35
 */
36
public class NbProgressBar extends JProgressBar implements ProgressUIWorker {
37
    boolean isSetup = false;
38
    boolean usedInStatusBar = false;
39
    
40
    /** Creates a new instance of NbProgressBar */
41
    public NbProgressBar() {
42
        super();
43
        setOrientation(JProgressBar.HORIZONTAL);
44
        setAlignmentX(0.5f);
45
        setAlignmentY(0.5f);
46
        Color fg = UIManager.getColor ("nbProgressBar.Foreground");
47
        if (fg != null) {
48
            setForeground(fg);
49
        }
50
        Color bg = UIManager.getColor ("nbProgressBar.Background");
51
        if (bg != null) {
52
            setBackground(bg);
53
        }
54
    }
55
    
56
    public void setUseInStatusBar(boolean use) {
57
        usedInStatusBar = use;
58
    }
59
    
60
    public Dimension getPreferredSize() {
61
        Dimension supers = super.getPreferredSize();
62
        if (usedInStatusBar) {
63
            supers.width = ListComponent.ITEM_WIDTH / 3;
64
        }
65
        return supers;
66
    }
67
68
    
69
//--- these are used only when dealing with extracted component, when in status bar this is not used.    
70
//------------------------------------
71
    
72
    public void processProgressEvent(ProgressEvent event) {
73
        if (event.getType() == ProgressEvent.TYPE_START || !isSetup  || event.isSwitched()) {
74
            setupBar(event.getSource(), this);
75
            isSetup = true;
76
        } 
77
        if (event.getType() == ProgressEvent.TYPE_PROGRESS) {
78
            if (event.getWorkunitsDone() > 0) {
79
                setValue(event.getWorkunitsDone());
80
            }
81
            setString(StatusLineComponent.getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
82
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
83
            boolean wasIndetermenite = isIndeterminate();
84
            setIndeterminate(false);
85
            setMaximum(event.getSource().getTotalUnits());
86
            setValue(event.getSource().getTotalUnits());
87
            if (wasIndetermenite) {
88
                setStringPainted(false);
89
            } else {
90
                setString(StatusLineComponent.getBarString(100, -1));
91
            }
92
        }
93
    }
94
95
    public void processSelectedProgressEvent(ProgressEvent event) {
96
        // ignore we'return always processing just one selected component
97
    }
98
    
99
    
100
    static void setupBar(InternalHandle handle, NbProgressBar bar) {
101
        int total = handle.getTotalUnits();
102
        if (total < 1) {
103
            // macosx workaround..            
104
            bar.setValue(bar.getMaximum());
105
            bar.setIndeterminate(true);
106
            bar.setStringPainted(false);
107
        } else {
108
            bar.setStringPainted(true);
109
            bar.setIndeterminate(false);
110
            bar.setMaximum(total);
111
            bar.setMinimum(0);
112
            bar.setValue(0);
113
        }
114
        bar.setString(" ");
115
    }    
116
}
(-)progressui/src/org/netbeans/modules/progress/ui/PopupPane.java (+278 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.modules.progress.ui;
22
23
import java.awt.Color;
24
import java.awt.Component;
25
import java.awt.Dimension;
26
import java.awt.Graphics;
27
import java.awt.GridLayout;
28
import java.awt.Insets;
29
import java.awt.Toolkit;
30
import java.awt.event.ActionEvent;
31
import java.awt.event.KeyEvent;
32
import java.util.HashSet;
33
import java.util.Iterator;
34
import javax.swing.AbstractAction;
35
import javax.swing.Action;
36
import javax.swing.BorderFactory;
37
import javax.swing.JComponent;
38
import javax.swing.JPanel;
39
import javax.swing.JScrollPane;
40
import javax.swing.KeyStroke;
41
import javax.swing.UIManager;
42
import javax.swing.border.Border;
43
import org.netbeans.progress.spi.InternalHandle;
44
45
/**
46
 *
47
 * @author mkleint
48
 */
49
public class PopupPane extends JScrollPane {
50
    private JPanel view;
51
    private HashSet<ListComponent> listComponents;
52
    /** Creates a new instance of PopupPane */
53
    private ListComponent selected;
54
    
55
    public PopupPane() {
56
        listComponents = new HashSet<ListComponent>();
57
        view = new JPanel();
58
        GridLayout grid = new GridLayout(0, 1);
59
        grid.setHgap(0);
60
        grid.setVgap(0);
61
        view.setLayout(grid);
62
        view.setBorder(BorderFactory.createEmptyBorder());
63
        setName("progresspopup"); //NOI18N
64
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
65
        setViewportView(view);
66
        setFocusable(true);
67
        setRequestFocusEnabled(true);
68
69
        Action down = new MoveDownAction();
70
        getActionMap().put("Move-Down", down);
71
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
72
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "Move-Down");
73
        
74
        Action up = new MoveUpAction();
75
        getActionMap().put("Move-Up", up);
76
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
77
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "Move-Up");
78
        Action cancel = new CancelAction();
79
        getActionMap().put("Cancel-Task", cancel);
80
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
81
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "Cancel-Task");
82
        
83
        Action select = new SelectAction();
84
        getActionMap().put("select-task", select);
85
        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
86
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "select-task");
87
        
88
        
89
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
90
//        addFocusListener(new FocusListener() {
91
//            public void focusLost(java.awt.event.FocusEvent e) {
92
//                System.out.println("popup focus gained temp?=" + e.isTemporary());
93
//            }
94
//
95
//            public void focusGained(java.awt.event.FocusEvent e) {
96
//                System.out.println("popup focus lost temporary?=" + e.isTemporary());
97
//            }
98
//            
99
//        });
100
    }
101
    
102
    public void addListComponent(ListComponent lst) {
103
        listComponents.add(lst);
104
        if (view.getComponentCount() > 0) {
105
            JComponent previous = (JComponent)view.getComponent(view.getComponentCount() - 1);
106
            previous.setBorder(new BottomLineBorder());
107
        }
108
        lst.setBorder(BorderFactory.createEmptyBorder());
109
        view.add(lst);
110
        if (listComponents.size() > 3) {
111
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
112
        } else {
113
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
114
        }
115
    }
116
    
117
    public void removeListComponent(InternalHandle handle) {
118
        Iterator it = listComponents.iterator();
119
        while (it.hasNext()) {
120
            ListComponent comp = (ListComponent)it.next();
121
            if (comp.getHandle() == handle) {
122
                view.remove(comp);
123
                it.remove();
124
                break;
125
            }
126
        }
127
        if (listComponents.size() > 3) {
128
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
129
        } else {
130
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
131
        }
132
    }
133
134
    public Dimension getPreferredSize() {
135
        int count = view.getComponentCount();
136
        int height = count > 0 ? view.getComponent(0).getPreferredSize().height : 0;
137
        int offset = count > 3 ? height * 3 + 5 : (count * height) + 5;
138
        // 22 is the width of the additional scrollbar
139
        return new Dimension(count >3 ? ListComponent.ITEM_WIDTH + 22 
140
                                      : ListComponent.ITEM_WIDTH + 2, offset);
141
    }
142
143
    /**
144
     * bold font is now used not only for explicitly selected items, but for any 
145
     * change in currently selected task.
146
     */
147
    public void updateBoldFont(InternalHandle handle) {
148
        Iterator it = listComponents.iterator();
149
        while (it.hasNext()) {
150
            ListComponent comp = (ListComponent)it.next();
151
            comp.markAsActive(handle == comp.getHandle());
152
        }
153
    }
154
    
155
    
156
    
157
    private static class BottomLineBorder implements Border {
158
        private Insets ins = new Insets(0, 0, 1, 0);
159
        private Color col = new Color(221, 229, 248);
160
        
161
        public BottomLineBorder () {}
162
        
163
        public Insets getBorderInsets(Component c) {
164
            return ins;
165
        }
166
167
        public boolean isBorderOpaque() {
168
            return false;
169
        }
170
171
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
172
           Color old = g.getColor();
173
           g.setColor(col);
174
           g.drawRect(x, y + height - 2,  width, 1);
175
           g.setColor(old);
176
        }
177
    }
178
    
179
    private int findIndex(Component comp) {
180
        Component[] comps = view.getComponents();
181
        for (int i = 0; i < comps.length; i++) {
182
            if (comps[i] == comp) {
183
                return i;
184
            }
185
        }
186
        return -1;
187
    }
188
189
    public void requestFocus() {
190
//#63666 - don't focus any of the tasks explicitly, wait for user action.
191
//        if (view.getComponentCount() > 1) {
192
//            if (selected == null || !selected.isDisplayable()) {
193
//                selected = (ListComponent)view.getComponent(0);
194
//            }
195
//            selected.requestFocus();
196
//        } else {
197
            super.requestFocus();
198
//        }
199
    }
200
    
201
    private class MoveDownAction extends AbstractAction {
202
        
203
        MoveDownAction() {
204
        }
205
         
206
        public void actionPerformed(ActionEvent actionEvent) {
207
            int index = -1;
208
            if (selected != null) {
209
                index = findIndex(selected);
210
            }
211
            index = index + 1;
212
            if (index >= PopupPane.this.view.getComponentCount()) {
213
                index = 0;
214
            }
215
            selected = (ListComponent)PopupPane.this.view.getComponent(index);
216
            selected.requestFocus();
217
        }
218
        
219
    }
220
    
221
    private class MoveUpAction extends AbstractAction {
222
        
223
        MoveUpAction() {
224
        }
225
         
226
        public void actionPerformed(ActionEvent actionEvent) {
227
            int index = PopupPane.this.view.getComponentCount();
228
            if (selected != null) {
229
                index = findIndex(selected);
230
//                selected.setBackground(new Color(249, 249, 249));
231
            }
232
            index = index - 1;
233
            if (index < 0) {
234
                index = PopupPane.this.view.getComponentCount() - 1;
235
            }
236
            selected = (ListComponent)PopupPane.this.view.getComponent(index);
237
            selected.requestFocus();
238
//            selected.setBackground(selectBgColor);
239
//            selected.scrollRectToVisible(selected.getBounds());
240
        }
241
    }
242
    
243
    private class CancelAction extends AbstractAction {
244
        public CancelAction () {}
245
        
246
        public void actionPerformed(ActionEvent actionEvent) {
247
            if (selected != null) {
248
                Action act = selected.getCancelAction();
249
                if (act != null) {
250
                    act.actionPerformed(actionEvent);
251
                } else {
252
                    Toolkit.getDefaultToolkit().beep();
253
                }
254
            }
255
        }
256
    }
257
258
    private class SelectAction extends AbstractAction {
259
        public SelectAction () {}
260
        
261
        public void actionPerformed(ActionEvent actionEvent) {
262
            if (selected != null) {
263
                selected.getHandle().requestExplicitSelection();
264
            }
265
        }
266
    }
267
    
268
    private class ViewAction extends AbstractAction {
269
        public ViewAction () {}
270
        
271
        public void actionPerformed(ActionEvent actionEvent) {
272
            if (selected != null) {
273
                selected.getHandle().requestView();
274
            }
275
        }
276
    }
277
    
278
}
(-)progressui/src/org/netbeans/modules/progress/ui/ProviderImpl.java (+44 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.modules.progress.ui;
21
22
import org.netbeans.progress.spi.ProgressUIWorker;
23
import org.netbeans.progress.spi.ProgressUIWorkerProvider;
24
import org.netbeans.progress.spi.ProgressUIWorkerWithModel;
25
26
/**
27
 *
28
 * @author mkleint
29
 */
30
public class ProviderImpl implements ProgressUIWorkerProvider {
31
    
32
    /** Creates a new instance of ProviderImpl */
33
    public ProviderImpl() {
34
    }
35
36
    public ProgressUIWorkerWithModel getDefaultWorker() {
37
        return new StatusLineComponent();
38
    }
39
40
    public ProgressUIWorker getExtractedComponentWorker() {
41
        return new NbProgressBar();
42
    }
43
    
44
}
(-)progressui/src/org/netbeans/modules/progress/ui/StatusLineComponent.java (+465 lines)
Line 1 Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
21
package org.netbeans.modules.progress.ui;
22
import java.awt.AWTEvent;
23
import java.awt.Component;
24
import java.awt.Container;
25
import java.awt.Cursor;
26
import java.awt.Dimension;
27
import java.awt.FlowLayout;
28
import java.awt.Frame;
29
import java.awt.Point;
30
import java.awt.Rectangle;
31
import java.awt.Toolkit;
32
import java.awt.event.AWTEventListener;
33
import java.awt.event.ActionEvent;
34
import java.awt.event.ComponentAdapter;
35
import java.awt.event.ComponentEvent;
36
import java.awt.event.KeyEvent;
37
import java.awt.event.MouseAdapter;
38
import java.awt.event.MouseEvent;
39
import java.awt.event.MouseListener;
40
import java.awt.event.WindowEvent;
41
import java.awt.event.WindowStateListener;
42
import java.util.HashMap;
43
import java.util.Map;
44
import javax.swing.AbstractAction;
45
import javax.swing.Action;
46
import javax.swing.BorderFactory;
47
import javax.swing.JComponent;
48
import javax.swing.JLabel;
49
import javax.swing.JPanel;
50
import javax.swing.JPopupMenu;
51
import javax.swing.JSeparator;
52
import javax.swing.JWindow;
53
import javax.swing.KeyStroke;
54
import javax.swing.Popup;
55
import javax.swing.SwingUtilities;
56
import javax.swing.event.ListDataEvent;
57
import javax.swing.event.ListDataListener;
58
import javax.swing.event.ListSelectionEvent;
59
import javax.swing.event.ListSelectionListener;
60
import org.netbeans.progress.spi.InternalHandle;
61
import org.netbeans.progress.spi.ProgressUIWorker;
62
import org.netbeans.progress.spi.ProgressEvent;
63
import org.netbeans.progress.module.ProgressListAction;
64
import org.netbeans.progress.spi.ProgressUIWorkerWithModel;
65
import org.netbeans.progress.spi.TaskModel;
66
import org.openide.DialogDisplayer;
67
import org.openide.NotifyDescriptor;
68
import org.openide.util.NbBundle;
69
import org.openide.util.Utilities;
70
import org.openide.windows.WindowManager;
71
72
73
/**
74
 *
75
 * @author Milos Kleint (mkleint@netbeans.org)
76
 */
77
public class StatusLineComponent extends JPanel implements ProgressUIWorkerWithModel {
78
    private NbProgressBar bar;
79
    private JLabel label;
80
    private JSeparator separator;
81
    private InternalHandle handle;
82
    private boolean showingPopup = false;
83
    private TaskModel model;
84
    private MouseListener mouseListener;
85
    private HideAWTListener hideListener;
86
    private Popup popup;
87
    private JWindow popupWindow;
88
    private PopupPane pane;
89
    private Map<InternalHandle, ListComponent> handleComponentMap;
90
    private final int prefferedHeight;
91
    /** Creates a new instance of StatusLineComponent */
92
    public StatusLineComponent() {
93
        handleComponentMap = new HashMap<InternalHandle, ListComponent>();
94
        label = new JLabel();
95
        label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
96
        bar = new NbProgressBar();
97
        bar.setUseInStatusBar(true);
98
        // tricks to figure out correct height.
99
        bar.setStringPainted(true);
100
        bar.setString("XXX");
101
        label.setText("XXX");
102
        prefferedHeight = Math.max(label.getPreferredSize().height, bar.getPreferredSize().height) + 2;
103
        
104
        bar.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
105
//        setBorder(BorderFactory.createLineBorder(Color.BLUE, 1));
106
        FlowLayout flay = new FlowLayout();
107
        flay.setVgap(1);
108
        flay.setHgap(5);
109
        setLayout(flay);
110
        // HACK - put smaller font inside the progress bar to keep
111
        // the height of the progressbar constant for determinate and indeterminate bars
112
//        Font fnt = UIManager.getFont("ProgressBar.font");
113
//        bar.setFont(fnt.deriveFont(fnt.getStyle(), fnt.getSize() - 3));
114
115
        mouseListener = new MListener();
116
        label.addMouseListener(mouseListener);
117
        bar.addMouseListener(mouseListener);
118
        addMouseListener(mouseListener);
119
        hideListener = new HideAWTListener();
120
        pane = new PopupPane();
121
        pane.getActionMap().put("HidePopup", new AbstractAction() {
122
            public void actionPerformed(ActionEvent actionEvent) {
123
//                System.out.println("escape pressed - hiding");
124
                hidePopup();
125
            }
126
        });
127
        pane.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup");
128
        pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "HidePopup");
129
        separator = new JSeparator(JSeparator.VERTICAL);
130
        separator.setPreferredSize(new Dimension(5, prefferedHeight));
131
        separator.setBorder(BorderFactory.createEmptyBorder(1, 0, 2, 0));
132
    }
133
    
134
    public Dimension getPreferredSize() {
135
        Dimension retValue;
136
        retValue = super.getPreferredSize();
137
        retValue.height = prefferedHeight;
138
        return retValue;
139
    }
140
141
    public Dimension getMinimumSize() {
142
        Dimension retValue;
143
        retValue = super.getMinimumSize();
144
        retValue.height = prefferedHeight;
145
        return retValue;
146
    }        
147
    
148
    public Dimension getMaximumSize() {
149
        Dimension retValue;
150
        retValue = super.getMaximumSize();
151
        retValue.height = prefferedHeight;
152
        return retValue;
153
    }        
154
    
155
    public void setModel(TaskModel mod) {
156
        model = mod;
157
        model.addListDataListener(new Listener());
158
        model.addListSelectionListener(new ListSelectionListener() {
159
            public void valueChanged(ListSelectionEvent e) {
160
                pane.updateBoldFont(model.getSelectedHandle());
161
            }
162
        });
163
    }
164
    
165
    private void setTooltipForAll() {
166
        int size = model.getSize();
167
        String key = "NbProgressBar.tooltip1"; //NOI18N
168
        if (size == 1) {
169
            key = "NbProgressBar.tooltip2"; //NOI18N
170
        }
171
        String text = NbBundle.getMessage(StatusLineComponent.class, key, new Integer(size));
172
        setToolTipText(text);
173
        label.setToolTipText(text);
174
        bar.setToolTipText(text);
175
    }
176
    
177
    public void processProgressEvent(ProgressEvent event) {
178
        if (event.getType() == ProgressEvent.TYPE_START) {
179
            createListItem(event.getSource());
180
        } else if (event.getType() == ProgressEvent.TYPE_PROGRESS || 
181
                   event.getType() == ProgressEvent.TYPE_SWITCH) {
182
            ListComponent comp = (ListComponent)handleComponentMap.get(event.getSource());
183
            if (comp == null) {
184
                createListItem(event.getSource());
185
                comp = (ListComponent)handleComponentMap.get(event.getSource());
186
            }
187
            comp.processProgressEvent(event);
188
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
189
            removeListItem(event.getSource());
190
            if (model.getSelectedHandle() != null && handle != model.getSelectedHandle()) {
191
                initiateComponent(model.getSelectedHandle().requestStateSnapshot());
192
            }
193
        }
194
        
195
    }
196
    
197
    public void processSelectedProgressEvent(ProgressEvent event) {
198
        if (event.getType() == ProgressEvent.TYPE_START) {
199
            initiateComponent(event);
200
            return;
201
        } else if (event.getType() == ProgressEvent.TYPE_FINISH) {
202
            //happens only when there's no more handles.
203
            hidePopup();
204
            removeAll();
205
            //#63393, 61940 fix - removeAll() just invalidates. seems to work without revalidate/repaint on some platforms, fail on others.
206
            revalidate();
207
            repaint();
208
            return;
209
        } else {
210
            if (event.getSource() != handle || event.isSwitched()) {
211
                initiateComponent(event);
212
            }
213
            if (event.getWorkunitsDone() > 0) {
214
               bar.setValue(event.getWorkunitsDone());
215
            }
216
            bar.setString(getBarString(event.getPercentageDone(), event.getEstimatedCompletion()));
217
            if (event.getDisplayName() != null) {
218
                label.setText(event.getDisplayName());
219
            }
220
        } 
221
    }
222
    
223
    static String formatEstimate(long estimate) {
224
        long minutes = estimate / 60;
225
        long seconds = estimate - (minutes * 60);
226
        return "" + minutes + (seconds < 10 ? ":0" : ":") + seconds;
227
    }
228
    
229
    static String getBarString(int percentage, long estimatedCompletion) {
230
        if (estimatedCompletion != -1) {
231
            return formatEstimate(estimatedCompletion);
232
        }
233
        if (percentage != -1) {
234
            return "" + percentage + "%";
235
        }
236
        return "";
237
    }
238
    
239
    private void initiateComponent(ProgressEvent event) {
240
        handle = event.getSource();
241
        boolean toShow = false;
242
        label.setText(handle.getDisplayName());
243
        if (label.getParent() == null) {
244
            add(label);
245
            toShow = true;
246
        }
247
        NbProgressBar.setupBar(event.getSource(), bar);
248
        if (bar.getParent() == null) {
249
            add(bar);
250
            toShow = true;
251
        }
252
        if (separator.getParent() == null) {
253
            add(separator);
254
            toShow = true;
255
        }
256
        if (toShow) {
257
            revalidate();
258
            repaint();
259
        }
260
    }
261
    
262
    private class Listener implements ListDataListener {
263
        public void intervalAdded(ListDataEvent e) {
264
            setTooltipForAll();
265
        }
266
        
267
        public void intervalRemoved(ListDataEvent e) {
268
            setTooltipForAll();
269
        }
270
        
271
        
272
        public void contentsChanged(ListDataEvent e) {
273
            setTooltipForAll();
274
        }
275
    }
276
    
277
    public void hidePopup() {
278
        if (popupWindow != null) {
279
//            popupWindow.getContentPane().removeAll();
280
            popupWindow.setVisible(false);
281
        }
282
        Toolkit.getDefaultToolkit().removeAWTEventListener(hideListener);
283
        WindowManager.getDefault().getMainWindow().removeWindowStateListener(hideListener);
284
        WindowManager.getDefault().getMainWindow().removeComponentListener(hideListener);
285
        showingPopup = false;
286
    }
287
    
288
    private void createListItem(InternalHandle handle) {
289
        ListComponent comp;
290
        if (handleComponentMap.containsKey(handle)) {
291
            // happens when we click to display on popup and there is a 
292
            // new handle waiting in the queue.
293
            comp = handleComponentMap.get(handle);
294
        } else {
295
            comp = new ListComponent(handle);
296
            handleComponentMap.put(handle, comp);
297
        }
298
        pane.addListComponent(comp);            
299
        pane.updateBoldFont(model.getSelectedHandle());
300
        if (showingPopup) {
301
            resizePopup();
302
        }
303
    }
304
    
305
    private void removeListItem(InternalHandle handle) {
306
        handleComponentMap.remove(handle);
307
        pane.removeListComponent(handle);
308
        pane.updateBoldFont(model.getSelectedHandle());
309
        if (showingPopup) {
310
            resizePopup();
311
        }
312
    }
313
314
    
315
    public void showPopup() {
316
        if (showingPopup) {
317
            return;
318
        }
319
        InternalHandle[] handles = model.getHandles();
320
        if (handles.length == 0) {
321
            // just in case..
322
            return;
323
        }
324
        showingPopup = true;
325
        
326
        // NOT using PopupFactory
327
        // 1. on linux, creates mediumweight popup taht doesn't refresh behind visible glasspane
328
        // 2. on mac, needs an owner frame otherwise hiding tooltip also hides the popup. (linux requires no owner frame to force heavyweight)
329
        // 3. the created window is not focusable window
330
        if (popupWindow == null) {
331
            popupWindow = new JWindow(WindowManager.getDefault().getMainWindow());
332
            popupWindow.getContentPane().add(pane);
333
        }
334
        Toolkit.getDefaultToolkit().addAWTEventListener(hideListener, AWTEvent.MOUSE_EVENT_MASK);
335
        WindowManager.getDefault().getMainWindow().addWindowStateListener(hideListener);
336
        WindowManager.getDefault().getMainWindow().addComponentListener(hideListener);
337
        resizePopup();
338
        popupWindow.setVisible(true);
339
        pane.requestFocus();
340
//        System.out.println("     window focusable=" + popupWindow.isFocusableWindow());
341
    }
342
    
343
    private void resizePopup() {
344
        popupWindow.pack();
345
        Point point = new Point(0,0);
346
        SwingUtilities.convertPointToScreen(point, this);
347
        Dimension dim = popupWindow.getSize();
348
        //#63265 
349
        Rectangle usableRect = Utilities.getUsableScreenBounds();
350
        Point loc = new Point(point.x + this.getSize().width + 4 - dim.width , point.y - dim.height - 5);
351
        if (! usableRect.contains(loc)) {
352
            loc = new Point(loc.x, point.y + 5 + this.getSize().height);
353
        }
354
            // +4 here because of the width of the close button in popup, we
355
            // want the progress bars to align visually.. but there's separator in status now..
356
        popupWindow.setLocation(loc);
357
//        System.out.println("count=" + count);
358
//        System.out.println("offset =" + offset);
359
    }
360
    
361
    private class HideAWTListener extends ComponentAdapter implements  AWTEventListener, WindowStateListener {
362
        public void eventDispatched(java.awt.AWTEvent aWTEvent) {
363
            if (aWTEvent instanceof MouseEvent) {
364
                MouseEvent mv = (MouseEvent)aWTEvent;
365
                if (mv.getClickCount() > 0) {
366
                    Component comp = (Component)aWTEvent.getSource();
367
                    Container par = SwingUtilities.getAncestorNamed("progresspopup", comp); //NOI18N
368
                    Container barpar = SwingUtilities.getAncestorOfClass(StatusLineComponent.class, comp);
369
                    if (par == null && barpar == null) {
370
                        hidePopup();
371
                    }
372
                }
373
            }
374
        }
375
376
        public void windowStateChanged(WindowEvent windowEvent) {
377
            if (showingPopup) {
378
                int oldState = windowEvent.getOldState();
379
                int newState = windowEvent.getNewState();
380
            
381
                if (((oldState & Frame.ICONIFIED) == 0) &&
382
                    ((newState & Frame.ICONIFIED) == Frame.ICONIFIED)) {
383
                    hidePopup();
384
//                } else if (((oldState & Frame.ICONIFIED) == Frame.ICONIFIED) && 
385
//                           ((newState & Frame.ICONIFIED) == 0 )) {
386
//                    //TODO remember we showed before and show again? I guess not worth the efford, not part of spec.
387
                }
388
            }
389
390
        }
391
        
392
        public void componentResized(ComponentEvent evt) {
393
            if (showingPopup) {
394
                resizePopup();
395
            }
396
        }
397
        
398
        public void componentMoved(ComponentEvent evt) {
399
            if (showingPopup) {
400
                resizePopup();
401
            }
402
        }        
403
        
404
    }
405
    
406
    private class MListener extends MouseAdapter {
407
        public void mouseClicked(java.awt.event.MouseEvent e) {
408
            if (e.getButton() != MouseEvent.BUTTON1) {
409
                showMenu(e);
410
            } else {
411
                if (showingPopup) {
412
                    hidePopup();
413
                } else {
414
                    showPopup();
415
                }
416
            }
417
        }
418
        
419
    }
420
    
421
    private void showMenu(MouseEvent e) {
422
        JPopupMenu popup = new JPopupMenu();
423
        popup.add(new ProgressListAction(NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.ShowProcessList"))); 
424
        popup.add(new ViewAction());
425
        popup.add(new CancelAction());
426
        popup.show((Component)e.getSource(), e.getX(), e.getY());
427
    }
428
    
429
  private class CancelAction extends AbstractAction {
430
        public CancelAction() {
431
            putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.Cancel"));
432
            setEnabled(handle == null ? false : handle.isAllowCancel());
433
            
434
        }
435
        public void actionPerformed(ActionEvent actionEvent) {
436
            InternalHandle hndl = handle;
437
            if (hndl !=null && hndl.getState() == InternalHandle.STATE_RUNNING) {
438
                String message = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question", handle.getDisplayName());
439
                String title = NbBundle.getMessage(StatusLineComponent.class, "Cancel_Question_Title");
440
                NotifyDescriptor dd = new NotifyDescriptor(message, title, 
441
                                           NotifyDescriptor.YES_NO_OPTION,
442
                                           NotifyDescriptor.QUESTION_MESSAGE, null, null);
443
                Object retType = DialogDisplayer.getDefault().notify(dd);
444
                if (retType == NotifyDescriptor.YES_OPTION && hndl.getState() == InternalHandle.STATE_RUNNING) {
445
                    hndl.requestCancel();
446
                }
447
            }
448
        }
449
    }
450
451
    private class ViewAction extends AbstractAction {
452
        public ViewAction() {
453
            putValue(Action.NAME, NbBundle.getMessage(StatusLineComponent.class, "StatusLineComponent.View"));
454
            setEnabled(handle == null ? false : handle.isAllowView());
455
            
456
        }
457
        public void actionPerformed(ActionEvent actionEvent) {
458
            if (handle != null) {
459
                handle.requestView();
460
            }
461
        }
462
    }    
463
    
464
465
}
(-)progressui/src/org/netbeans/modules/progress/ui/layer.xml (+4 lines)
Line 1 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
3
<filesystem>
4
</filesystem>

Return to bug 78605