major optimization updates
[debian/openrocket] / src / net / sf / openrocket / util / OpenFileWorker.java
1 package net.sf.openrocket.util;
2
3 import java.io.BufferedInputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FilterInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InterruptedIOException;
10
11 import javax.swing.SwingWorker;
12
13 import net.sf.openrocket.document.OpenRocketDocument;
14 import net.sf.openrocket.file.RocketLoader;
15 import net.sf.openrocket.gui.main.ExceptionHandler;
16 import net.sf.openrocket.logging.LogHelper;
17 import net.sf.openrocket.startup.Application;
18
19
20 /**
21  * A SwingWorker thread that opens a rocket design file.
22  * 
23  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
24  */
25 public class OpenFileWorker extends SwingWorker<OpenRocketDocument, Void> {
26         private static final LogHelper log = Application.getLogger();
27         
28         private final File file;
29         private final InputStream stream;
30         private final RocketLoader loader;
31         
32         public OpenFileWorker(File file, RocketLoader loader) {
33                 this.file = file;
34                 this.stream = null;
35                 this.loader = loader;
36         }
37         
38         
39         public OpenFileWorker(InputStream stream, RocketLoader loader) {
40                 this.stream = stream;
41                 this.file = null;
42                 this.loader = loader;
43         }
44         
45         public RocketLoader getRocketLoader() {
46                 return loader;
47         }
48         
49         @Override
50         protected OpenRocketDocument doInBackground() throws Exception {
51                 InputStream is;
52                 
53                 // Get the correct input stream
54                 if (file != null) {
55                         is = new FileInputStream(file);
56                 } else {
57                         is = stream;
58                 }
59                 
60                 // Buffer stream unless already buffered
61                 if (!(is instanceof BufferedInputStream)) {
62                         is = new BufferedInputStream(is);
63                 }
64                 
65                 // Encapsulate in a ProgressInputStream
66                 is = new ProgressInputStream(is);
67                 
68                 try {
69                         return loader.load(is);
70                 } finally {
71                         try {
72                                 is.close();
73                         } catch (Exception e) {
74                                 ExceptionHandler.handleErrorCondition("Error closing file", e);
75                         }
76                 }
77         }
78         
79         
80
81
82         private class ProgressInputStream extends FilterInputStream {
83                 
84                 private final int size;
85                 private int readBytes = 0;
86                 private int progress = -1;
87                 
88                 protected ProgressInputStream(InputStream in) {
89                         super(in);
90                         int s;
91                         try {
92                                 s = in.available();
93                         } catch (IOException e) {
94                                 log.info("Exception while estimating available bytes!", e);
95                                 s = 0;
96                         }
97                         size = Math.max(s, 1);
98                 }
99                 
100                 
101
102                 @Override
103                 public int read() throws IOException {
104                         int c = in.read();
105                         if (c >= 0) {
106                                 readBytes++;
107                                 setProgress();
108                         }
109                         if (isCancelled()) {
110                                 throw new InterruptedIOException("OpenFileWorker was cancelled");
111                         }
112                         return c;
113                 }
114                 
115                 @Override
116                 public int read(byte[] b, int off, int len) throws IOException {
117                         int n = in.read(b, off, len);
118                         if (n > 0) {
119                                 readBytes += n;
120                                 setProgress();
121                         }
122                         if (isCancelled()) {
123                                 throw new InterruptedIOException("OpenFileWorker was cancelled");
124                         }
125                         return n;
126                 }
127                 
128                 @Override
129                 public int read(byte[] b) throws IOException {
130                         int n = in.read(b);
131                         if (n > 0) {
132                                 readBytes += n;
133                                 setProgress();
134                         }
135                         if (isCancelled()) {
136                                 throw new InterruptedIOException("OpenFileWorker was cancelled");
137                         }
138                         return n;
139                 }
140                 
141                 @Override
142                 public long skip(long n) throws IOException {
143                         long nr = in.skip(n);
144                         if (nr > 0) {
145                                 readBytes += nr;
146                                 setProgress();
147                         }
148                         if (isCancelled()) {
149                                 throw new InterruptedIOException("OpenFileWorker was cancelled");
150                         }
151                         return nr;
152                 }
153                 
154                 @Override
155                 public synchronized void reset() throws IOException {
156                         in.reset();
157                         readBytes = size - in.available();
158                         setProgress();
159                         if (isCancelled()) {
160                                 throw new InterruptedIOException("OpenFileWorker was cancelled");
161                         }
162                 }
163                 
164                 
165
166                 private void setProgress() {
167                         int p = MathUtil.clamp(readBytes * 100 / size, 0, 100);
168                         if (progress != p) {
169                                 progress = p;
170                                 OpenFileWorker.this.setProgress(progress);
171                         }
172                 }
173         }
174 }