File Source: DCCSendWindow.java
/*
P/P * Method: com.dmdirc.addons.dcc.DCCSendWindow__static_init
*/
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.addons.dcc;
24
25 import com.dmdirc.actions.ActionManager;
26 import com.dmdirc.addons.dcc.actions.DCCActions;
27 import com.dmdirc.config.IdentityManager;
28 import com.dmdirc.parser.irc.IRCParser;
29 import com.dmdirc.parser.irc.SocketState;
30 import com.dmdirc.parser.irc.callbacks.interfaces.ISocketClosed;
31
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.io.File;
35
36 import javax.swing.JButton;
37 import javax.swing.JLabel;
38 import javax.swing.JOptionPane;
39 import javax.swing.JProgressBar;
40
41 import net.miginfocom.swing.MigLayout;
42
43 /**
44 * This class links DCC Send objects to a window.
45 *
46 * @author Shane 'Dataforce' McCormack
47 */
48 public class DCCSendWindow extends DCCFrame implements DCCSendInterface, ActionListener, ISocketClosed {
49 /** The DCCSend object we are a window for */
50 private final DCCSend dcc;
51
52 /** Other Nickname */
53 private final String otherNickname;
54
55 /** Total data transfered */
56 private volatile long transferCount = 0;
57
58 /** Time Started */
59 private long timeStarted = 0;
60
61 /** Progress Bar */
62 private final JProgressBar progress = new JProgressBar();
63
64 /** Status Label */
65 private final JLabel status = new JLabel("Status: Waiting");
66
67 /** Speed Label */
68 private final JLabel speed = new JLabel("Speed: Unknown");
69
70 /** Time Label */
71 private final JLabel remaining = new JLabel("Time Remaining: Unknown");
72
73 /** Time Taken */
74 private final JLabel taken = new JLabel("Time Taken: 00:00");
75
76 /** Button */
77 private final JButton button = new JButton("Cancel");
78
79 /** Plugin that this send belongs to. */
80 private final DCCPlugin myPlugin;
81
82 /** IRC Parser that caused this send */
83 private IRCParser parser = null;
84
85 /**
86 * Creates a new instance of DCCSendWindow with a given DCCSend object.
87 *
88 * @param plugin the DCC Plugin responsible for this window
89 * @param dcc The DCCSend object this window wraps around
90 * @param title The title of this window
91 * @param targetNick Nickname of target
92 * @param parser The IRC parser that initiated this send
93 */
94 public DCCSendWindow(final DCCPlugin plugin, final DCCSend dcc, final String title, final String targetNick, final IRCParser parser) {
/*
P/P * Method: void com.dmdirc.addons.dcc.DCCSendWindow(DCCPlugin, DCCSend, String, String, IRCParser)
*
* Preconditions:
* dcc != null
* init'ed(dcc.filename)
* init'ed(dcc.transferType)
* init'ed(plugin.container)
* plugin != null
* (soft) plugin.childFrames != null
*
* Presumptions:
* com.dmdirc.addons.ui_swing.components.frames.TextFrame:getContentPane(...)@192 != null
* com.dmdirc.config.IdentityManager:getGlobalConfig(...)@138 init'ed
* com.dmdirc.parser.irc.IRCParser:getCallbackManager(...)@101 != null
* (soft) init'ed(com/dmdirc/FrameContainer.java.awt.Color.BLACK)
*
* Postconditions:
* dcc.handler == this
* dcc.handler != null
* plugin.container == One-of{old plugin.container, &new DCCPlugin$3(createContainer#1)}
* plugin.container != null
* this.button == &new JButton(DCCSendWindow#6)
* this.changer == &new FrameContainer$IconChanger(FrameContainer#2)
* this.config != null
* this.dcc == dcc
* this.dcc != null
* this.icon in Addr_Set{&"dcc-receive-inactive",&"dcc-send-inactive"}
* ...
*
* Test Vectors:
* parser: Addr_Set{null}, Inverse{null}
*/
95 super(plugin, title, dcc.getType() == DCCSend.TransferType.SEND ? "dcc-send-inactive" : "dcc-receive-inactive");
96 this.dcc = dcc;
97 this.parser = parser;
98 this.myPlugin = plugin;
99
100 if (parser != null) {
101 parser.getCallbackManager().addNonCriticalCallback("onSocketClosed", this);
102 }
103 dcc.setHandler(this);
104
105 otherNickname = targetNick;
106
107 getContentPane().setLayout(new MigLayout());
108
109 progress.setMinimum(0);
110 progress.setMaximum(100);
111 progress.setStringPainted(true);
112 progress.setValue(0);
113
114 if (dcc.getType() == DCCSend.TransferType.SEND) {
115 getContentPane().add(new JLabel("Sending: "+dcc.getShortFileName()), "wrap");
116 getContentPane().add(new JLabel("To: "+targetNick), "wrap");
117 } else {
118 getContentPane().add(new JLabel("Recieving: "+dcc.getShortFileName()), "wrap");
119 getContentPane().add(new JLabel("From: "+targetNick), "wrap");
120 }
121 getContentPane().add(status, "wrap");
122 getContentPane().add(speed, "wrap");
123 getContentPane().add(remaining, "wrap");
124 getContentPane().add(taken, "wrap");
125 getContentPane().add(progress, "growx, wrap");
126
127 button.addActionListener(this);
128 getContentPane().add(button, "wrap, align right");
129
130 plugin.addWindow(this);
131 }
132
133 /** {@inheritDoc} */
134 @Override
135 public void onSocketClosed(final IRCParser tParser) {
136 // Remove our reference to the parser (and its reference to us)
/*
P/P * Method: void onSocketClosed(IRCParser)
*
* Preconditions:
* this.parser != null
* this.button != null
*
* Presumptions:
* com.dmdirc.parser.irc.IRCParser:getCallbackManager(...)@137 != null
*
* Postconditions:
* this.parser == null
*
* Test Vectors:
* java.lang.String:equals(...)@140: {0}, {1}
*/
137 parser.getCallbackManager().delAllCallback(this);
138 parser = null;
139 // Can't resend without the parser.
140 if ("Resend".equals(button.getText())) {
141 button.setText("Close Window");
142 }
143 }
144
145 /**
146 * Get the DCCSend Object associated with this window
147 *
148 * @return The DCCSend Object associated with this window
149 */
150 public DCCSend getDCC() {
/*
P/P * Method: DCCSend getDCC()
*
* Postconditions:
* return_value == this.dcc
* init'ed(return_value)
*/
151 return dcc;
152 }
153
154 /** {@inheritDoc} */
155 @Override
156 public void actionPerformed(final ActionEvent e) {
/*
P/P * Method: void actionPerformed(ActionEvent)
*
* Preconditions:
* e != null
* (soft) init'ed(this.dcc.address)
* (soft) init'ed(this.dcc.fileIn)
* (soft) init'ed(this.dcc.filename)
* (soft) init'ed(this.dcc.port)
* (soft) init'ed(this.dcc.serverSocket)
* (soft) init'ed(this.dcc.socket)
* (soft) init'ed(this.dcc.startpos)
* (soft) this.button != null
* (soft) this.dcc != null
* ...
*
* Presumptions:
* com.dmdirc.config.IdentityManager:getGlobalConfig(...)@187 != null
* com.dmdirc.parser.irc.IRCParser:getIRCStringConverter(...)@176 != null
* init'ed(com.dmdirc.parser.irc.SocketState.OPEN)
* java.awt.event.ActionEvent:getActionCommand(...)@157 != null
* java.awt.event.ActionEvent:getActionCommand(...)@165 != null
* ...
*
* Postconditions:
* java.lang.Integer:toString(...)._tainted == 0
* this.dcc.address == One-of{old this.dcc.address, 0}
* init'ed(this.dcc.address)
* this.dcc.fileIn == One-of{old this.dcc.fileIn, &new DataInputStream(setFileName#2), null}
* init'ed(this.dcc.fileIn)
* possibly_updated(this.dcc.fileOut)
* this.dcc.filename == old this.dcc.filename
* init'ed(this.dcc.filename)
* this.dcc.handler.timeStarted == old this.dcc.handler.timeStarted
* possibly_updated(this.dcc.in)
* ...
*
* Test Vectors:
* this.parser: Addr_Set{null}, Inverse{null}
* com.dmdirc.config.ConfigManager:getOptionBool(...)@187: {0}, {1}
* com.dmdirc.parser.irc.IRCStringConverter:equalsIgnoreCase(...)@176: {0}, {1}
* java.lang.String:equals(...)@157: {0}, {1}
* java.lang.String:equals(...)@165: {0}, {1}
* java.lang.String:equals(...)@199: {0}, {1}
*/
157 if (e.getActionCommand().equals("Cancel")) {
158 if (dcc.getType() == DCCSend.TransferType.SEND) {
159 button.setText("Resend");
160 } else {
161 button.setText("Close Window");
162 }
163 status.setText("Status: Cancelled");
164 dcc.close();
165 } else if (e.getActionCommand().equals("Resend")) {
166 button.setText("Cancel");
167 status.setText("Status: Resending...");
168 synchronized (this) {
169 transferCount = 0;
170 }
171 dcc.reset();
172 if (parser != null && parser.getSocketState() == SocketState.OPEN) {
173 final String myNickname = parser.getMyNickname();
174 // Check again incase we have changed nickname to the same nickname that
175 // this send is for.
176 if (parser.getIRCStringConverter().equalsIgnoreCase(otherNickname, myNickname)) {
/*
P/P * Method: void com.dmdirc.addons.dcc.DCCSendWindow$1(DCCSendWindow)
*/
177 final Thread errorThread = new Thread(new Runnable() {
178 /** {@inheritDoc} */
179 @Override
180 public void run() {
/*
P/P * Method: void run()
*/
181 JOptionPane.showMessageDialog(null, "You can't DCC yourself.", "DCC Error", JOptionPane.ERROR_MESSAGE);
182 }
183 });
184 errorThread.start();
185 return;
186 } else {
187 if (IdentityManager.getGlobalConfig().getOptionBool(plugin.getDomain(), "send.reverse")) {
188 parser.sendCTCP(otherNickname, "DCC", "SEND \""+(new File(dcc.getFileName())).getName()+"\" "+DCC.ipToLong(myPlugin.getListenIP(parser))+" 0 "+dcc.getFileSize()+" "+dcc.makeToken()+((dcc.isTurbo()) ? " T" : ""));
189 return;
190 } else if (plugin.listen(dcc)) {
191 parser.sendCTCP(otherNickname, "DCC", "SEND \""+(new File(dcc.getFileName())).getName()+"\" "+DCC.ipToLong(myPlugin.getListenIP(parser))+" "+dcc.getPort()+" "+dcc.getFileSize()+((dcc.isTurbo()) ? " T" : ""));
192 return;
193 }
194 }
195 } else {
196 status.setText("Status: Resend failed.");
197 button.setText("Close Window");
198 }
199 } else if (e.getActionCommand().equals("Close Window")) {
200 close();
201 }
202 }
203
204 /**
205 * Called when data is sent/recieved
206 *
207 * @param dcc The DCCSend that this message is from
208 * @param bytes The number of new bytes that were transfered
209 */
210 @Override
211 public void dataTransfered(final DCCSend dcc, final int bytes) {
212 final double percent;
/*
P/P * Method: void dataTransfered(DCCSend, int)
*
* Preconditions:
* (float) (dcc.size) != +0
* init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* dcc != null
* init'ed(dcc.size)
* init'ed(dcc.startpos)
* init'ed(dcc.transferType)
* this.dcc != null
* init'ed(this.dcc.size)
* init'ed(this.dcc.startpos)
* this.progress != null
* ...
*
* Presumptions:
* (int) (java.lang.Math:floor(...)@226) in {-231..232-1}
* bytes + this.transferCount in {-263..264-1}
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* init'ed(this.transferCount)
* new ArrayList(ServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1).servers == null
*/
213 synchronized (this) {
214 transferCount += bytes;
215 percent = (100.00 / dcc.getFileSize()) * (transferCount + dcc.getFileStart());
216 }
217
218 if (dcc.getType() == DCCSend.TransferType.SEND) {
219 status.setText("Status: Sending");
220 } else {
221 status.setText("Status: Recieving");
222 }
223
224 updateSpeedAndTime();
225
226 progress.setValue((int)Math.floor(percent));
227
228 ActionManager.processEvent(DCCActions.DCC_SEND_DATATRANSFERED, null, this, bytes);
229 }
230
231 /**
232 * Update the transfer speed, time remaining and time taken labels.
233 */
234 public void updateSpeedAndTime() {
/*
P/P * Method: void updateSpeedAndTime()
*
* Preconditions:
* this.dcc != null
* init'ed(this.dcc.size)
* init'ed(this.dcc.startpos)
* this.remaining != null
* this.speed != null
* this.taken != null
* init'ed(this.timeStarted)
*
* Presumptions:
* (int) (java.lang.Math:floor(...)@255) in {-263..264-1}
* (this.dcc.startpos - this.dcc.size) + this.transferCount in {-264+1..263}
*/
235 final long time = (System.currentTimeMillis() - timeStarted) / 1000;
236 final double bytesPerSecond;
237 synchronized (this) {
238 bytesPerSecond = (time > 0) ? (transferCount / time) : transferCount;
239 }
240
241 if (bytesPerSecond > 1048576) {
242 speed.setText(String.format("Speed: %.2f MB/s", (bytesPerSecond/1048576)));
243 } else if (bytesPerSecond > 1024) {
244 speed.setText(String.format("Speed: %.2f KB/s", (bytesPerSecond/1024)));
245 } else {
246 speed.setText(String.format("Speed: %f B/s", bytesPerSecond));
247 }
248
249 final long remaningBytes;
250 synchronized (this) {
251 remaningBytes = dcc.getFileSize() - dcc.getFileStart() - transferCount;
252 }
253 final double remainingSeconds = (bytesPerSecond > 0) ? (remaningBytes / bytesPerSecond) : 1;
254
255 remaining.setText(String.format("Time Remaining: %s", duration((int) Math.floor(remainingSeconds))));
256 taken.setText(String.format("Time Taken: %s", timeStarted == 0 ? "N/A" : duration(time)));
257 }
258
259 /**
260 * Get the duration in seconds as a string.
261 *
262 * @param secondsInput to get duration for
263 * @return Duration as a string
264 */
265 private String duration(final long secondsInput) {
/*
P/P * Method: String duration(long)
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* return_value == &java.lang.StringBuilder:toString(...)
*
* Test Vectors:
* secondsInput: {-263..3_599}, {3_600..264-1}
* secondsInput/3_600: {-2_562_047_788_015_215..0}, {1..5_124_095_576_030_431}
* secondsInput/60: {-153_722_867_280_912_930..59}, {60..307_445_734_561_825_860}
*/
266 final StringBuilder result = new StringBuilder();
267 final long hours = (secondsInput / 3600);
268 final long minutes = (secondsInput / 60 % 60);
269 final long seconds = (secondsInput % 60);
270
271 if (hours > 0) { result.append(hours+":"); }
272 result.append(String.format("%0,2d:%0,2d",minutes,seconds));
273
274 return result.toString();
275 }
276
277 /**
278 * Called when the socket is closed
279 *
280 * @param dcc The DCCSend that this message is from
281 */
282 @Override
283 public void socketClosed(final DCCSend dcc) {
/*
P/P * Method: void socketClosed(DCCSend)
*
* Preconditions:
* init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* init'ed(this.windowClosing)
* (soft) com.dmdirc.addons.dcc.actions.DCCActions__static_init.new DCCActions(DCCActions__static_init#7).type != null
* (soft) dcc != null
* (soft) init'ed(dcc.size)
* (soft) init'ed(dcc.transferType)
* (soft) init'ed(com/dmdirc/ServerManager.me)
* (soft) this.button != null
* (soft) this.config != null
* (soft) this.dcc != null
* ...
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* this.icon == One-of{old this.icon, &"dcc-send-done", &"dcc-receive-done", &"dcc-send-failed", &"dcc-receive-failed"}
* new ArrayList(ServerManager#1) num objects == undefined
* new ArrayList(ServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1) num objects == new ArrayList(ServerManager#1) num objects
* new ServerManager(getServerManager#1).servers == undefined
* new ServerManager(getServerManager#1).servers == null
*
* Test Vectors:
* this.windowClosing: {1}, {0}
*/
284 ActionManager.processEvent(DCCActions.DCC_SEND_SOCKETCLOSED, null, this);
285 if (!isWindowClosing()) {
286 synchronized (this) {
287 if (transferCount == dcc.getFileSize()) {
288 status.setText("Status: Transfer Compelete.");
289 progress.setValue(100);
290 setIcon(dcc.getType() == DCCSend.TransferType.SEND ? "dcc-send-done" : "dcc-receive-done");
291 button.setText("Close Window");
292 } else {
293 status.setText("Status: Transfer Failed.");
294 setIcon(dcc.getType() == DCCSend.TransferType.SEND ? "dcc-send-failed" : "dcc-receive-failed");
295 if (dcc.getType() == DCCSend.TransferType.SEND) {
296 button.setText("Resend");
297 } else {
298 button.setText("Close Window");
299 }
300 }
301 }
302 updateSpeedAndTime();
303 }
304 }
305
306 /**
307 * Called when the socket is opened
308 *
309 * @param dcc The DCCSend that this message is from
310 */
311 @Override
312 public void socketOpened(final DCCSend dcc) {
/*
P/P * Method: void socketOpened(DCCSend)
*
* Preconditions:
* init'ed(com/dmdirc/actions/ActionManager.killSwitch)
* dcc != null
* init'ed(dcc.transferType)
* this.config != null
* this.listeners != null
* this.status != null
* (soft) com.dmdirc.addons.dcc.actions.DCCActions__static_init.new DCCActions(DCCActions__static_init#8).type != null
* (soft) init'ed(com/dmdirc/ServerManager.me)
*
* Postconditions:
* com/dmdirc/ServerManager.me == old com/dmdirc/ServerManager.me
* this.icon == One-of{&"dcc-send-active", &"dcc-receive-active"}
* this.icon in Addr_Set{&"dcc-receive-active",&"dcc-send-active"}
* init'ed(this.timeStarted)
* new ArrayList(ServerManager#1) num objects == undefined
* new ArrayList(ServerManager#1) num objects == 0, if init'ed
* new ServerManager(getServerManager#1) num objects == new ArrayList(ServerManager#1) num objects
* new ServerManager(getServerManager#1).servers == undefined
* new ServerManager(getServerManager#1).servers == null
*/
313 ActionManager.processEvent(DCCActions.DCC_SEND_SOCKETOPENED, null, this);
314 status.setText("Status: Socket Opened");
315 timeStarted = System.currentTimeMillis();
316 setIcon(dcc.getType() == DCCSend.TransferType.SEND ? "dcc-send-active" : "dcc-receive-active");
317 }
318
319 /**
320 * Closes this container (and it's associated frame).
321 */
322 @Override
323 public void windowClosing() {
/*
P/P * Method: void windowClosing()
*
* Preconditions:
* this.myWindow != null
* init'ed(this.plugin.container)
* this.dcc != null
* this.dcc.serverSocketSem != null
* this.plugin != null
* (soft) init'ed(this.dcc.serverSocket)
* (soft) init'ed(this.dcc.socket)
* (soft) this.dcc.serverListeningSem != null
* (soft) this.plugin.childFrames != null
*
* Postconditions:
* possibly_updated(this.dcc.in)
* possibly_updated(this.dcc.out)
* this.dcc.serverSocket == null
* this.dcc.socket == null
* this.myWindow == null
* this.plugin.container == One-of{old this.plugin.container, null}
* init'ed(this.plugin.container)
* this.windowClosing == 1
*/
324 super.windowClosing();
325 dcc.removeFromSends();
326 dcc.close();
327 }
328 }
SofCheck Inspector Build Version : 2.17854
| DCCSendWindow.java |
2009-Jun-25 01:54:24 |
| DCCSendWindow.class |
2009-Sep-02 17:04:17 |
| DCCSendWindow$1.class |
2009-Sep-02 17:04:17 |