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