ColumnTypes.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /*******************************************************************************
  2. /
  3. / File: ColumnTypes.h
  4. /
  5. / Description: Experimental classes that implement particular column/field
  6. / data types for use in BColumnListView.
  7. /
  8. / Copyright 2000+, Be Incorporated, All Rights Reserved
  9. /
  10. *******************************************************************************/
  11. #include "ColumnTypes.h"
  12. #include <View.h>
  13. #include <parsedate.h>
  14. #include <stdio.h>
  15. #define kTEXT_MARGIN 8
  16. BTitledColumn::BTitledColumn(const char* title, float width, float minWidth,
  17. float maxWidth, alignment align)
  18. : BColumn(width, minWidth, maxWidth, align),
  19. fTitle(title)
  20. {
  21. font_height fh;
  22. be_plain_font->GetHeight(&fh);
  23. fFontHeight = fh.descent + fh.leading;
  24. }
  25. void
  26. BTitledColumn::DrawTitle(BRect rect, BView* parent)
  27. {
  28. float width = rect.Width() - (2 * kTEXT_MARGIN);
  29. BString out_string(fTitle);
  30. parent->TruncateString(&out_string, B_TRUNCATE_END, width + 2);
  31. DrawString(out_string.String(), parent, rect);
  32. }
  33. void
  34. BTitledColumn::GetColumnName(BString* into) const
  35. {
  36. *into = fTitle;
  37. }
  38. void
  39. BTitledColumn::DrawString(const char* string, BView* parent, BRect rect)
  40. {
  41. float width = rect.Width() - (2 * kTEXT_MARGIN);
  42. float y;
  43. BFont font;
  44. font_height finfo;
  45. parent->GetFont(&font);
  46. font.GetHeight(&finfo);
  47. y = rect.top + ((rect.Height() - (finfo.ascent + finfo.descent + finfo.leading)) / 2)
  48. + (finfo.ascent + finfo.descent) - 2;
  49. switch (Alignment()) {
  50. default:
  51. case B_ALIGN_LEFT:
  52. parent->MovePenTo(rect.left + kTEXT_MARGIN, y);
  53. break;
  54. case B_ALIGN_CENTER:
  55. parent->MovePenTo(rect.left + kTEXT_MARGIN + ((width - font.StringWidth(string)) / 2), y);
  56. break;
  57. case B_ALIGN_RIGHT:
  58. parent->MovePenTo(rect.right - kTEXT_MARGIN - font.StringWidth(string), y);
  59. break;
  60. }
  61. parent->DrawString(string);
  62. }
  63. void
  64. BTitledColumn::SetTitle(const char* title)
  65. {
  66. fTitle.SetTo(title);
  67. }
  68. void
  69. BTitledColumn::Title(BString* forTitle) const
  70. {
  71. if (forTitle)
  72. forTitle->SetTo(fTitle.String());
  73. }
  74. float
  75. BTitledColumn::FontHeight() const
  76. {
  77. return fFontHeight;
  78. }
  79. float
  80. BTitledColumn::GetPreferredWidth(BField *_field, BView* parent) const
  81. {
  82. return parent->StringWidth(fTitle.String()) + 2 * kTEXT_MARGIN;
  83. }
  84. // #pragma mark -
  85. BStringField::BStringField(const char* string)
  86. :
  87. fWidth(0),
  88. fString(string),
  89. fClippedString(string)
  90. {
  91. }
  92. void
  93. BStringField::SetString(const char* val)
  94. {
  95. fString = val;
  96. fClippedString = "";
  97. fWidth = 0;
  98. }
  99. const char*
  100. BStringField::String() const
  101. {
  102. return fString.String();
  103. }
  104. void
  105. BStringField::SetWidth(float width)
  106. {
  107. fWidth = width;
  108. }
  109. float
  110. BStringField::Width()
  111. {
  112. return fWidth;
  113. }
  114. void
  115. BStringField::SetClippedString(const char* val)
  116. {
  117. fClippedString = val;
  118. }
  119. bool
  120. BStringField::HasClippedString() const
  121. {
  122. return !fClippedString.IsEmpty();
  123. }
  124. const char*
  125. BStringField::ClippedString()
  126. {
  127. return fClippedString.String();
  128. }
  129. // #pragma mark -
  130. BStringColumn::BStringColumn(const char* title, float width, float minWidth,
  131. float maxWidth, uint32 truncate, alignment align)
  132. : BTitledColumn(title, width, minWidth, maxWidth, align),
  133. fTruncate(truncate)
  134. {
  135. }
  136. void
  137. BStringColumn::DrawField(BField* _field, BRect rect, BView* parent)
  138. {
  139. float width = rect.Width() - (2 * kTEXT_MARGIN);
  140. BStringField* field = static_cast<BStringField*>(_field);
  141. float fieldWidth = field->Width();
  142. bool updateNeeded = width != fieldWidth;
  143. if (updateNeeded) {
  144. BString out_string(field->String());
  145. float preferredWidth = parent->StringWidth(out_string.String());
  146. if (width < preferredWidth) {
  147. parent->TruncateString(&out_string, fTruncate, width + 2);
  148. field->SetClippedString(out_string.String());
  149. } else
  150. field->SetClippedString("");
  151. field->SetWidth(width);
  152. }
  153. DrawString(field->HasClippedString() ? field->ClippedString()
  154. : field->String(), parent, rect);
  155. }
  156. float
  157. BStringColumn::GetPreferredWidth(BField *_field, BView* parent) const
  158. {
  159. BStringField* field = static_cast<BStringField*>(_field);
  160. return parent->StringWidth(field->String()) + 2 * kTEXT_MARGIN;
  161. }
  162. int
  163. BStringColumn::CompareFields(BField* field1, BField* field2)
  164. {
  165. return ICompare(((BStringField*)field1)->String(),
  166. (((BStringField*)field2)->String()));
  167. }
  168. bool
  169. BStringColumn::AcceptsField(const BField *field) const
  170. {
  171. return static_cast<bool>(dynamic_cast<const BStringField*>(field));
  172. }
  173. // #pragma mark -
  174. BDateField::BDateField(time_t *t)
  175. :
  176. fTime(*localtime(t)),
  177. fUnixTime(*t),
  178. fSeconds(0),
  179. fClippedString(""),
  180. fWidth(0)
  181. {
  182. fSeconds = mktime(&fTime);
  183. }
  184. void
  185. BDateField::SetWidth(float width)
  186. {
  187. fWidth = width;
  188. }
  189. float
  190. BDateField::Width()
  191. {
  192. return fWidth;
  193. }
  194. void
  195. BDateField::SetClippedString(const char* val)
  196. {
  197. fClippedString = val;
  198. }
  199. const char*
  200. BDateField::ClippedString()
  201. {
  202. return fClippedString.String();
  203. }
  204. time_t
  205. BDateField::Seconds()
  206. {
  207. return fSeconds;
  208. }
  209. time_t
  210. BDateField::UnixTime()
  211. {
  212. return fUnixTime;
  213. }
  214. // #pragma mark -
  215. BDateColumn::BDateColumn(const char* title, float width, float minWidth,
  216. float maxWidth, alignment align)
  217. : BTitledColumn(title, width, minWidth, maxWidth, align),
  218. fTitle(title)
  219. {
  220. }
  221. const char *kTIME_FORMATS[] = {
  222. "%A, %B %d %Y, %I:%M:%S %p", // Monday, July 09 1997, 05:08:15 PM
  223. "%a, %b %d %Y, %I:%M:%S %p", // Mon, Jul 09 1997, 05:08:15 PM
  224. "%a, %b %d %Y, %I:%M %p", // Mon, Jul 09 1997, 05:08 PM
  225. "%b %d %Y, %I:%M %p", // Jul 09 1997, 05:08 PM
  226. "%m/%d/%y, %I:%M %p", // 07/09/97, 05:08 PM
  227. "%m/%d/%y", // 07/09/97
  228. NULL
  229. };
  230. void
  231. BDateColumn::DrawField(BField* _field, BRect rect, BView* parent)
  232. {
  233. float width = rect.Width() - (2 * kTEXT_MARGIN);
  234. BDateField* field = (BDateField*)_field;
  235. if (field->Width() != rect.Width()) {
  236. char dateString[256];
  237. time_t curtime = field->UnixTime();
  238. tm time_data;
  239. BFont font;
  240. parent->GetFont(&font);
  241. localtime_r(&curtime, &time_data);
  242. for (int32 index = 0; ; index++) {
  243. if (!kTIME_FORMATS[index])
  244. break;
  245. strftime(dateString, 256, kTIME_FORMATS[index], &time_data);
  246. if (font.StringWidth(dateString) <= width)
  247. break;
  248. }
  249. if (font.StringWidth(dateString) > width) {
  250. BString out_string(dateString);
  251. parent->TruncateString(&out_string, B_TRUNCATE_MIDDLE, width + 2);
  252. strcpy(dateString, out_string.String());
  253. }
  254. field->SetClippedString(dateString);
  255. field->SetWidth(width);
  256. }
  257. DrawString(field->ClippedString(), parent, rect);
  258. }
  259. int
  260. BDateColumn::CompareFields(BField* field1, BField* field2)
  261. {
  262. return((BDateField*)field1)->Seconds() - ((BDateField*)field2)->Seconds();
  263. }
  264. // #pragma mark -
  265. BSizeField::BSizeField(off_t size)
  266. :
  267. fSize(size)
  268. {
  269. }
  270. void
  271. BSizeField::SetSize(off_t size)
  272. {
  273. fSize = size;
  274. }
  275. off_t
  276. BSizeField::Size()
  277. {
  278. return fSize;
  279. }
  280. // #pragma mark -
  281. BSizeColumn::BSizeColumn(const char* title, float width, float minWidth,
  282. float maxWidth, alignment align)
  283. : BTitledColumn(title, width, minWidth, maxWidth, align)
  284. {
  285. }
  286. const int64 kKB_SIZE = 1024;
  287. const int64 kMB_SIZE = 1048576;
  288. const int64 kGB_SIZE = 1073741824;
  289. const int64 kTB_SIZE = kGB_SIZE * kKB_SIZE;
  290. const char *kSIZE_FORMATS[] = {
  291. "%.2f %s",
  292. "%.1f %s",
  293. "%.f %s",
  294. "%.f%s",
  295. 0
  296. };
  297. void
  298. BSizeColumn::DrawField(BField* _field, BRect rect, BView* parent)
  299. {
  300. char str[256];
  301. float width = rect.Width() - (2 * kTEXT_MARGIN);
  302. BFont font;
  303. BString string;
  304. off_t size = ((BSizeField*)_field)->Size();
  305. parent->GetFont(&font);
  306. if (size < kKB_SIZE) {
  307. sprintf(str, "%" B_PRId64 " bytes", size);
  308. if (font.StringWidth(str) > width)
  309. sprintf(str, "%" B_PRId64 " B", size);
  310. } else {
  311. const char* suffix;
  312. float float_value;
  313. if (size >= kTB_SIZE) {
  314. suffix = "TB";
  315. float_value = (float)size / kTB_SIZE;
  316. } else if (size >= kGB_SIZE) {
  317. suffix = "GB";
  318. float_value = (float)size / kGB_SIZE;
  319. } else if (size >= kMB_SIZE) {
  320. suffix = "MB";
  321. float_value = (float)size / kMB_SIZE;
  322. } else {
  323. suffix = "KB";
  324. float_value = (float)size / kKB_SIZE;
  325. }
  326. for (int32 index = 0; ; index++) {
  327. if (!kSIZE_FORMATS[index])
  328. break;
  329. sprintf(str, kSIZE_FORMATS[index], float_value, suffix);
  330. // strip off an insignificant zero so we don't get readings
  331. // such as 1.00
  332. char *period = 0;
  333. char *tmp (NULL);
  334. for (tmp = str; *tmp; tmp++) {
  335. if (*tmp == '.')
  336. period = tmp;
  337. }
  338. if (period && period[1] && period[2] == '0') {
  339. // move the rest of the string over the insignificant zero
  340. for (tmp = &period[2]; *tmp; tmp++)
  341. *tmp = tmp[1];
  342. }
  343. if (font.StringWidth(str) <= width)
  344. break;
  345. }
  346. }
  347. string = str;
  348. parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2);
  349. DrawString(string.String(), parent, rect);
  350. }
  351. int
  352. BSizeColumn::CompareFields(BField* field1, BField* field2)
  353. {
  354. return ((BSizeField*)field1)->Size() - ((BSizeField*)field2)->Size();
  355. }
  356. // #pragma mark -
  357. BIntegerField::BIntegerField(int32 number)
  358. :
  359. fInteger(number)
  360. {
  361. }
  362. void
  363. BIntegerField::SetValue(int32 value)
  364. {
  365. fInteger = value;
  366. }
  367. int32
  368. BIntegerField::Value()
  369. {
  370. return fInteger;
  371. }
  372. // #pragma mark -
  373. BIntegerColumn::BIntegerColumn(const char* title, float width, float minWidth,
  374. float maxWidth, alignment align)
  375. : BTitledColumn(title, width, minWidth, maxWidth, align)
  376. {
  377. }
  378. void
  379. BIntegerColumn::DrawField(BField *field, BRect rect, BView* parent)
  380. {
  381. char formatted[256];
  382. float width = rect.Width() - (2 * kTEXT_MARGIN);
  383. BString string;
  384. sprintf(formatted, "%d", (int)((BIntegerField*)field)->Value());
  385. string = formatted;
  386. parent->TruncateString(&string, B_TRUNCATE_MIDDLE, width + 2);
  387. DrawString(string.String(), parent, rect);
  388. }
  389. int
  390. BIntegerColumn::CompareFields(BField *field1, BField *field2)
  391. {
  392. return (((BIntegerField*)field1)->Value() - ((BIntegerField*)field2)->Value());
  393. }
  394. // #pragma mark -
  395. GraphColumn::GraphColumn(const char* name, float width, float minWidth,
  396. float maxWidth, alignment align)
  397. : BIntegerColumn(name, width, minWidth, maxWidth, align)
  398. {
  399. }
  400. void
  401. GraphColumn::DrawField(BField* field, BRect rect, BView* parent)
  402. {
  403. int number = ((BIntegerField*)field)->Value();
  404. if (number > 100)
  405. number = 100;
  406. else if (number < 0)
  407. number = 0;
  408. BRect graphRect(rect);
  409. graphRect.InsetBy(5, 3);
  410. parent->StrokeRect(graphRect);
  411. if (number > 0) {
  412. graphRect.InsetBy(1, 1);
  413. float val = graphRect.Width() * (float) number / 100;
  414. graphRect.right = graphRect.left + val;
  415. parent->SetHighColor(0, 0, 190);
  416. parent->FillRect(graphRect);
  417. }
  418. parent->SetDrawingMode(B_OP_INVERT);
  419. parent->SetHighColor(128, 128, 128);
  420. char numstr[256];
  421. sprintf(numstr, "%d%%", number);
  422. float width = be_plain_font->StringWidth(numstr);
  423. parent->MovePenTo(rect.left + rect.Width() / 2 - width / 2, rect.bottom - FontHeight());
  424. parent->DrawString(numstr);
  425. }
  426. // #pragma mark -
  427. BBitmapField::BBitmapField(BBitmap *bitmap)
  428. :
  429. fBitmap(bitmap)
  430. {
  431. }
  432. const BBitmap*
  433. BBitmapField::Bitmap()
  434. {
  435. return fBitmap;
  436. }
  437. void
  438. BBitmapField::SetBitmap(BBitmap* bitmap)
  439. {
  440. fBitmap = bitmap;
  441. }
  442. // #pragma mark -
  443. BBitmapColumn::BBitmapColumn(const char* title, float width, float minWidth,
  444. float maxWidth, alignment align)
  445. : BTitledColumn(title, width, minWidth, maxWidth, align)
  446. {
  447. }
  448. void
  449. BBitmapColumn::DrawField(BField* field, BRect rect, BView* parent)
  450. {
  451. BBitmapField *bitmapField = static_cast<BBitmapField *>(field);
  452. const BBitmap *bitmap = bitmapField->Bitmap();
  453. if (bitmap != NULL) {
  454. float x = 0.0;
  455. BRect r = bitmap->Bounds();
  456. float y = rect.top + ((rect.Height() - r.Height()) / 2);
  457. switch (Alignment()) {
  458. default:
  459. case B_ALIGN_LEFT:
  460. x = rect.left + kTEXT_MARGIN;
  461. break;
  462. case B_ALIGN_CENTER:
  463. x = rect.left + ((rect.Width() - r.Width()) / 2);
  464. break;
  465. case B_ALIGN_RIGHT:
  466. x = rect.right - kTEXT_MARGIN - r.Width();
  467. break;
  468. }
  469. // setup drawing mode according to bitmap color space,
  470. // restore previous mode after drawing
  471. drawing_mode oldMode = parent->DrawingMode();
  472. if (bitmap->ColorSpace() == B_RGBA32
  473. || bitmap->ColorSpace() == B_RGBA32_BIG) {
  474. parent->SetDrawingMode(B_OP_ALPHA);
  475. parent->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
  476. } else {
  477. parent->SetDrawingMode(B_OP_OVER);
  478. }
  479. parent->DrawBitmap(bitmap, BPoint(x, y));
  480. parent->SetDrawingMode(oldMode);
  481. }
  482. }
  483. int
  484. BBitmapColumn::CompareFields(BField* /*field1*/, BField* /*field2*/)
  485. {
  486. // Comparing bitmaps doesn't really make sense...
  487. return 0;
  488. }
  489. bool
  490. BBitmapColumn::AcceptsField(const BField *field) const
  491. {
  492. return static_cast<bool>(dynamic_cast<const BBitmapField*>(field));
  493. }