1 | /** |
---|
2 | * Copyright (C) 2007 Bryan Varner |
---|
3 | * |
---|
4 | * Permission is hereby granted, free of charge, to any person obtaining |
---|
5 | * a copy of this software and associated documentation files (the |
---|
6 | * "Software"), to deal in the Software without restriction, including |
---|
7 | * without limitation the rights to use, copy, modify, merge, publish, |
---|
8 | * distribute, sublicense, and/or sell copies of the Software, and to |
---|
9 | * permit persons to whom the Software is furnished to do so, subject to |
---|
10 | * the following conditions: |
---|
11 | * |
---|
12 | * The above copyright notice and this permission notice shall be included |
---|
13 | * in all copies or substantial portions of the Software. |
---|
14 | * |
---|
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
---|
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
---|
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
---|
19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
---|
20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
---|
21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
---|
22 | * |
---|
23 | * $Id: TRTransfer.cpp 5457 2008-03-31 17:59:16Z charles $ |
---|
24 | */ |
---|
25 | |
---|
26 | #include "TRTransfer.h" |
---|
27 | |
---|
28 | #include <Font.h> |
---|
29 | |
---|
30 | #include <malloc.h> |
---|
31 | #include <stdio.h> |
---|
32 | |
---|
33 | /** |
---|
34 | * BListItem that renders Transfer status. |
---|
35 | */ |
---|
36 | TRTransfer::TRTransfer(const char *fullpath, node_ref node, tr_torrent_t *torrentRef) : BListItem(0, false), cachedNodeRef(node) { |
---|
37 | fBaselineOffset = 0.0f; |
---|
38 | fLineSpacing = 0.0f; |
---|
39 | torrent = torrentRef; |
---|
40 | |
---|
41 | cachedPath = new BString(fullpath); |
---|
42 | fStatusLock = new BLocker("Status Locker", true); |
---|
43 | |
---|
44 | fStatus = (tr_stat_t*)calloc(1, sizeof(tr_stat_t)); |
---|
45 | const tr_info_t *info = tr_torrentInfo(torrent); |
---|
46 | fName = new BString("<unknown name>"); |
---|
47 | fName->SetTo(info->name); |
---|
48 | |
---|
49 | fBarColor.red = 50; |
---|
50 | fBarColor.green = 150; |
---|
51 | fBarColor.blue = 255; |
---|
52 | fBarColor.alpha = 255; |
---|
53 | |
---|
54 | fTimeStr = (char*)calloc(78, sizeof(char)); |
---|
55 | fTransStr = (char*)calloc(78, sizeof(char)); |
---|
56 | } |
---|
57 | |
---|
58 | |
---|
59 | TRTransfer::~TRTransfer() { |
---|
60 | if (fStatusLock->Lock()) { |
---|
61 | free(fStatus); |
---|
62 | fStatusLock->Unlock(); |
---|
63 | delete fStatusLock; |
---|
64 | } |
---|
65 | delete cachedPath; |
---|
66 | delete fName; |
---|
67 | } |
---|
68 | |
---|
69 | |
---|
70 | void TRTransfer::Update(BView *owner, const BFont *font) { |
---|
71 | BListItem::Update(owner, font); |
---|
72 | SetHeight(BListItem::Height() * 4); |
---|
73 | |
---|
74 | font_height height; |
---|
75 | font->GetHeight(&height); |
---|
76 | |
---|
77 | fBaselineOffset = height.leading + height.ascent; |
---|
78 | fLineSpacing = height.descent; |
---|
79 | } |
---|
80 | |
---|
81 | |
---|
82 | /** |
---|
83 | * Sets the transfer information to render. |
---|
84 | * Returns a bool signaling the view is dirty after the update. |
---|
85 | * |
---|
86 | * The view is determined to be dirty if the transfer |
---|
87 | * status, percentDone, eta or the "shade" (even or odd) |
---|
88 | * position in the list changes from the previous state. |
---|
89 | * If the tr_stat_t is in fact different then the new, full |
---|
90 | * status is memcpy'd overtop the existing code. |
---|
91 | * |
---|
92 | * This is a thread-safe function, as all writing to the |
---|
93 | * local fStatus requires a successful Lock on fStatusLock. |
---|
94 | */ |
---|
95 | bool TRTransfer::UpdateStatus(const tr_stat_t *stat, bool shade) { |
---|
96 | bool dirty = false; |
---|
97 | if (fStatusLock->Lock()) { |
---|
98 | if (fStatus->status != stat->status || |
---|
99 | fStatus->percentDone != stat->percentDone || |
---|
100 | fStatus->eta != stat->eta || |
---|
101 | fShade != shade) |
---|
102 | { |
---|
103 | memcpy(fStatus, stat, sizeof(tr_stat_t)); |
---|
104 | dirty = true; |
---|
105 | } |
---|
106 | fStatusLock->Unlock(); |
---|
107 | fShade = shade; |
---|
108 | } |
---|
109 | return dirty; |
---|
110 | } |
---|
111 | |
---|
112 | bool TRTransfer::IsRunning() { |
---|
113 | return (fStatus != NULL && |
---|
114 | (fStatus->status & (TR_STATUS_CHECK_WAIT | TR_STATUS_CHECK | |
---|
115 | TR_STATUS_DOWNLOAD | TR_STATUS_SEED | TR_STATUS_STOPPING))); |
---|
116 | } |
---|
117 | |
---|
118 | |
---|
119 | /** |
---|
120 | * Renders (Draws) the current status into the BListView. |
---|
121 | */ |
---|
122 | void TRTransfer::DrawItem(BView *owner, BRect frame, bool) { |
---|
123 | rgb_color col; |
---|
124 | col.red = 255; |
---|
125 | col.green = 255; |
---|
126 | col.blue = 255; |
---|
127 | |
---|
128 | owner->PushState(); |
---|
129 | |
---|
130 | // Draw the background... |
---|
131 | if (IsSelected()) { |
---|
132 | owner->SetLowColor(tint_color(col, B_DARKEN_2_TINT)); |
---|
133 | } else if (fShade) { |
---|
134 | owner->SetLowColor(tint_color(tint_color(col, B_DARKEN_1_TINT), B_LIGHTEN_2_TINT)); |
---|
135 | } else { |
---|
136 | owner->SetLowColor(col); |
---|
137 | } |
---|
138 | owner->FillRect(frame, B_SOLID_LOW); |
---|
139 | |
---|
140 | // Draw the informational text... |
---|
141 | owner->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR)); |
---|
142 | BPoint textLoc = frame.LeftTop(); |
---|
143 | textLoc.y += (fBaselineOffset / 2); |
---|
144 | textLoc += BPoint(2, fBaselineOffset); |
---|
145 | |
---|
146 | if (fStatus != NULL && fStatusLock->Lock()) { |
---|
147 | owner->DrawString(fName->String(), textLoc); |
---|
148 | |
---|
149 | if (fStatus->status & TR_STATUS_STOPPED ) { |
---|
150 | sprintf(fTimeStr, "Paused (%.2f %%)", 100 * fStatus->percentDone); |
---|
151 | } else if (fStatus->status & TR_STATUS_CHECK_WAIT ) { |
---|
152 | sprintf(fTimeStr, "Waiting To Check Existing Files (%.2f %%)", |
---|
153 | 100 * fStatus->percentDone); |
---|
154 | } else if (fStatus->status & TR_STATUS_CHECK ) { |
---|
155 | sprintf(fTimeStr, "Checking Existing Files (%.2f %%)", |
---|
156 | 100 * fStatus->percentDone); |
---|
157 | } else if (fStatus->status & TR_STATUS_DOWNLOAD) { |
---|
158 | if (fStatus->eta < 0 ) { |
---|
159 | sprintf(fTimeStr, "--:--:-- Remaining (%.2f %%Complete)", |
---|
160 | 100 * fStatus->percentDone); |
---|
161 | } else { |
---|
162 | sprintf(fTimeStr, "%02d:%02d:%02d Remaining (%.2f %%Complete)", |
---|
163 | fStatus->eta / 3600, (fStatus->eta / 60) % 60, |
---|
164 | fStatus->eta % 60, 100 * fStatus->percentDone); |
---|
165 | } |
---|
166 | } else if (fStatus->status & TR_STATUS_SEED) { |
---|
167 | sprintf(fTimeStr, "Seeding"); |
---|
168 | } else if (fStatus->status & TR_STATUS_STOPPING) { |
---|
169 | sprintf(fTimeStr, "Stopping..."); |
---|
170 | } else { |
---|
171 | fTimeStr[0] = '\0'; |
---|
172 | } |
---|
173 | |
---|
174 | textLoc.x = frame.Width() - owner->StringWidth(fTimeStr) - 2; |
---|
175 | owner->DrawString(fTimeStr, textLoc); |
---|
176 | |
---|
177 | if (fStatus->status & (TR_STATUS_DOWNLOAD | TR_STATUS_SEED | TR_STATUS_CHECK | TR_STATUS_CHECK_WAIT )) { |
---|
178 | // Move to the left of the bottom line. |
---|
179 | textLoc.Set(frame.left + 2, |
---|
180 | frame.top + fBaselineOffset * 3 + (2 * fLineSpacing) + (fBaselineOffset / 2)); |
---|
181 | sprintf(fTransStr, "DL: %.2f KB/s (from %i of %i peer%s)", |
---|
182 | fStatus->rateDownload, fStatus->peersSendingToUs, fStatus->peersTotal, |
---|
183 | (fStatus->peersTotal == 1) ? "" : "s"); |
---|
184 | owner->DrawString(fTransStr, textLoc); |
---|
185 | |
---|
186 | sprintf(fTransStr, "UL: %.2f KB/s", fStatus->rateUpload); |
---|
187 | textLoc.x = frame.Width() - owner->StringWidth(fTransStr) - 2; |
---|
188 | owner->DrawString(fTransStr, textLoc); |
---|
189 | } |
---|
190 | |
---|
191 | /* |
---|
192 | * Progress Bar - Mercilessly ripped from the Haiku source code, and |
---|
193 | * modified to handle selection tinting, and list item position shading. |
---|
194 | */ |
---|
195 | // Custom setup (Transmission Added) |
---|
196 | BRect rect(frame.left + 2, frame.top + fBaselineOffset + fLineSpacing + (fBaselineOffset / 2), |
---|
197 | frame.Width() - 2, frame.top + fBaselineOffset * 2 + fLineSpacing + (fBaselineOffset / 2)); |
---|
198 | |
---|
199 | // First bevel |
---|
200 | owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_1_TINT)); |
---|
201 | if (IsSelected()) { |
---|
202 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
203 | } |
---|
204 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
205 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
206 | |
---|
207 | owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); |
---|
208 | if (IsSelected()) { |
---|
209 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
210 | } |
---|
211 | owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
212 | owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f)); |
---|
213 | |
---|
214 | rect.InsetBy(1.0f, 1.0f); |
---|
215 | |
---|
216 | // Second bevel |
---|
217 | owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_4_TINT)); |
---|
218 | if (IsSelected()) { |
---|
219 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
220 | } |
---|
221 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
222 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
223 | |
---|
224 | owner->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); |
---|
225 | if (IsSelected()) { |
---|
226 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
227 | } |
---|
228 | owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
229 | owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f)); |
---|
230 | |
---|
231 | rect.InsetBy(1.0f, 1.0f); |
---|
232 | |
---|
233 | // Filling |
---|
234 | owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_MAX_TINT)); |
---|
235 | if (IsSelected()) { |
---|
236 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
237 | } |
---|
238 | owner->FillRect(rect); |
---|
239 | |
---|
240 | if (fStatus->percentDone != 0.0f) { |
---|
241 | rect.right = rect.left + (float)ceil(fStatus->percentDone * (rect.Width() - 4)), |
---|
242 | |
---|
243 | // Bevel |
---|
244 | owner->SetHighColor(tint_color(fBarColor, B_LIGHTEN_2_TINT)); |
---|
245 | if (IsSelected()) { |
---|
246 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
247 | } |
---|
248 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top)); |
---|
249 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
250 | |
---|
251 | owner->SetHighColor(tint_color(fBarColor, B_DARKEN_2_TINT)); |
---|
252 | if (IsSelected()) { |
---|
253 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
254 | } |
---|
255 | owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom)); |
---|
256 | owner->StrokeLine(BPoint(rect.right, rect.top)); |
---|
257 | |
---|
258 | rect.InsetBy(1.0f, 1.0f); |
---|
259 | |
---|
260 | // Filling |
---|
261 | owner->SetHighColor(fBarColor); |
---|
262 | if (IsSelected()) { |
---|
263 | owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT)); |
---|
264 | } |
---|
265 | owner->FillRect(rect); |
---|
266 | } |
---|
267 | |
---|
268 | fStatusLock->Unlock(); |
---|
269 | } else { |
---|
270 | owner->DrawString("loading...", textLoc); |
---|
271 | } |
---|
272 | |
---|
273 | owner->PopState(); |
---|
274 | } |
---|