float TruncTimeBase(BString* outString, int64 value, const View* view, float width) { float resultWidth = width + 1; time_t timeValue = (time_t)value; // Find the longest possible format that will fit the available space struct { BDateFormatStyle dateStyle; BTimeFormatStyle timeStyle; } formats[] = { { B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT }, { B_LONG_DATE_FORMAT, B_SHORT_TIME_FORMAT }, { B_MEDIUM_DATE_FORMAT, B_SHORT_TIME_FORMAT }, { B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT }, }; BString date; BDateTimeFormat formatter; for (unsigned int i = 0; i < B_COUNT_OF(formats); ++i) { if (formatter.Format(date, timeValue, formats[i].dateStyle, formats[i].timeStyle) == B_OK) { resultWidth = view->StringWidth(date.String(), date.Length()); if (resultWidth <= width) { // Found a format that fits the available space, stop searching break; } } } // If we couldn't fit the date, try with just the time // TODO we could use only the time for "today" dates if (resultWidth > width && BDateFormat().Format(date, timeValue, B_SHORT_DATE_FORMAT) == B_OK) { resultWidth = view->StringWidth(date.String(), date.Length()); } if (resultWidth > width) { // even the shortest format string didn't do it, insert ellipsis resultWidth = TruncStringBase(outString, date.String(), (ssize_t)date.Length(), view, width); } else *outString = date; return resultWidth; }
float TruncTimeBase(BString *result, int64 value, const View *view, float width) { TrackerSettings settings; FormatSeparator separator = settings.TimeFormatSeparator(); DateOrder order = settings.DateOrderFormat(); bool clockIs24hr = settings.ClockIs24Hr(); float resultWidth = 0; char buffer[256]; time_t timeValue = (time_t)value; tm timeData; // use reentrant version of localtime to avoid having to have a semaphore // (localtime uses a global structure to do it's conversion) localtime_r(&timeValue, &timeData); BString timeFormat; for (int32 index = 0; ; index++) { if (TimeFormat(timeFormat, index, separator, order, clockIs24hr) != B_OK) break; strftime(buffer, 256, timeFormat.String(), &timeData); resultWidth = view->StringWidth(buffer); if (resultWidth <= width) break; } if (resultWidth > width) { // even the shortest format string didn't do it, insert ellipsis resultWidth = TruncStringBase(result, buffer, (ssize_t)strlen(buffer), view, width); } else *result = buffer; return resultWidth; }
float TruncFileSizeBase(BString* outString, int64 value, const View* view, float width) { // ToDo: If slow, replace float divisions with shifts // if fast enough, try fitting more decimal places. // ToDo: Update string_for_size() in libshared to be able to // handle this case. BString buffer; // format file size value if (value == kUnknownSize) { *outString = "-"; return view->StringWidth("-"); } else if (value < kKBSize) { static BStringFormat format(B_TRANSLATE( "{0, plural, one{# byte} other{# bytes}}")); format.Format(buffer, value); if (view->StringWidth(buffer.String()) > width) buffer.SetToFormat(B_TRANSLATE("%Ld B"), value); } else { const char* suffix; float doubleValue; if (value >= kTBSize) { suffix = B_TRANSLATE("TiB"); doubleValue = (double)value / kTBSize; } else if (value >= kGBSize) { suffix = B_TRANSLATE("GiB"); doubleValue = (double)value / kGBSize; } else if (value >= kMBSize) { suffix = B_TRANSLATE("MiB"); doubleValue = (double)value / kMBSize; } else { ASSERT(value >= kKBSize); suffix = B_TRANSLATE("KiB"); doubleValue = (double)value / kKBSize; } for (int32 index = 0; ; index++) { if (kSizeFormats[index] == 0) break; buffer.SetToFormat(kSizeFormats[index], doubleValue, suffix); // strip off an insignificant zero so we don't get readings // such as 1.00 char* period = 0; for (char* tmp = const_cast<char*>(buffer.String()); *tmp != '\0'; tmp++) { if (*tmp == '.') period = tmp; } if (period && period[1] && period[2] == '0') // move the rest of the string over the insignificant zero for (char* tmp = &period[2]; *tmp; tmp++) *tmp = tmp[1]; float resultWidth = view->StringWidth(buffer); if (resultWidth <= width) { *outString = buffer.String(); return resultWidth; } } } return TruncStringBase(outString, buffer.String(), buffer.Length(), view, width, (uint32)B_TRUNCATE_END); }
status_t WidgetAttributeText::AttrAsString(const Model* model, BString* outString, const char* attrName, int32 attrType, float width, BView* view, int64* resultingValue) { int64 value; status_t error = model->InitCheck(); if (error != B_OK) return error; switch (attrType) { case B_TIME_TYPE: if (strcmp(attrName, kAttrStatModified) == 0) value = model->StatBuf()->st_mtime; else if (strcmp(attrName, kAttrStatCreated) == 0) value = model->StatBuf()->st_crtime; else { TRESPASS(); // not yet supported return B_ERROR; } TruncTimeBase(outString, value, view, width); if (resultingValue) *resultingValue = value; return B_OK; case B_STRING_TYPE: if (strcmp(attrName, kAttrPath) == 0) { BEntry entry(model->EntryRef()); BPath path; BString tmp; if (entry.InitCheck() == B_OK && entry.GetPath(&path) == B_OK) { tmp = path.Path(); TruncateLeaf(&tmp); } else tmp = "-"; if (width > 0) { TruncStringBase(outString, tmp.String(), tmp.Length(), view, width); } else *outString = tmp.String(); return B_OK; } break; case kSizeType: // TruncFileSizeBase(outString, model->StatBuf()->st_size, view, // width); return B_OK; break; default: TRESPASS(); // not yet supported return B_ERROR; } TRESPASS(); return B_ERROR; }
float WidgetAttributeText::TruncString(BString* outString, const char* inString, int32 length, const BPoseView* view, float width, uint32 truncMode) { return TruncStringBase(outString, inString, length, view, width, truncMode); }
float TruncFileSizeBase(BString *result, int64 value, const View *view, float width) { // ToDo: // if slow, replace float divisions with shifts // if fast enough, try fitting more decimal places // format file size value char buffer[1024]; if (value == kUnknownSize) { *result = "-"; return view->StringWidth("-"); } else if (value < kKBSize) { sprintf(buffer, "%Ld bytes", value); if (view->StringWidth(buffer) > width) sprintf(buffer, "%Ld B", value); } else { const char *suffix; float floatValue; if (value >= kTBSize) { suffix = "TB"; floatValue = (float)value / kTBSize; } else if (value >= kGBSize) { suffix = "GB"; floatValue = (float)value / kGBSize; } else if (value >= kMBSize) { suffix = "MB"; floatValue = (float)value / kMBSize; } else { ASSERT(value >= kKBSize); suffix = "KB"; floatValue = (float)value / kKBSize; } for (int32 index = 0; ; index++) { if (!kSizeFormats[index]) break; sprintf(buffer, kSizeFormats[index], floatValue, suffix); // strip off an insignificant zero so we don't get readings // such as 1.00 char *period = 0; for (char *tmp = buffer; *tmp; tmp++) { if (*tmp == '.') period = tmp; } if (period && period[1] && period[2] == '0') // move the rest of the string over the insignificant zero for (char *tmp = &period[2]; *tmp; tmp++) *tmp = tmp[1]; float resultWidth = view->StringWidth(buffer); if (resultWidth <= width) { *result = buffer; return resultWidth; } } } return TruncStringBase(result, buffer, (ssize_t)strlen(buffer), view, width, (uint32)B_TRUNCATE_END); }
float WidgetAttributeText::TruncString(BString *result, const char *str, int32 length, const BPoseView *view, float width, uint32 truncMode) { return TruncStringBase(result, str, length, view, width, truncMode); }