* The type ahead mechanism did not work correctly in list view mode: instead

of taking the contents of the columns, it would always use the file name
  instead.
* That uncovered another bug, though: WidgetText::Text() tried to cast everything
  to StringAttributeText, but GenericAttributeText is actually used for most
  columns.
* Therefore, GenericAttributeText is now a subclass from StringAttributeText.
* Extended the type ahead to take other columns into account, and made it also
  find strings in the middle (like a filter) as a second choice.
* Whitespace cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28180 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-10-16 20:18:20 +00:00
parent 1e2bc11e99
commit 49ad25b392
7 changed files with 225 additions and 115 deletions
+39 -22
View File
@@ -2166,7 +2166,7 @@ BPoseView::MessageReceived(BMessage *message)
BPose *pose = fSelectionList->FirstItem(); BPose *pose = fSelectionList->FirstItem();
if (pose) { if (pose) {
pose->EditFirstWidget(BPoint(0, pose->EditFirstWidget(BPoint(0,
fPoseList->IndexOf(pose) * fListElemHeight), this); fPoseList->IndexOf(pose) * fListElemHeight), this);
} }
break; break;
} }
@@ -6017,33 +6017,50 @@ BPoseView::FindNextMatch(int32 *matchingIndex, bool reverse)
BPose * BPose *
BPoseView::FindBestMatch(int32 *index) BPoseView::FindBestMatch(int32 *index)
{ {
char bestSoFar[B_FILE_NAME_LENGTH] = { 0 };
BPose *poseToSelect = NULL; BPose *poseToSelect = NULL;
float bestScore = -1;
BColumn *firstColumn = FirstColumn(); int32 count = fPoseList->CountItems();
size_t matchLength = strlen(sMatchString);
// loop through all poses to find match // loop through all poses to find match
int32 count = fPoseList->CountItems(); for (int32 j = 0; j < CountColumns(); j++) {
for (int32 i = 0; i < count; i++) { BColumn *column = ColumnAt(j);
BPose *pose = fPoseList->ItemAt(i);
const char * text;
if (ViewMode() == kListMode)
text = pose->TargetModel()->Name();
else {
ModelNodeLazyOpener modelOpener(pose->TargetModel());
BTextWidget *widget = pose->WidgetFor(firstColumn, this, modelOpener);
if (widget)
text = widget->Text();
else
text = pose->TargetModel()->Name();
}
if (strcasecmp(text, sMatchString) >= 0) for (int32 i = 0; i < count; i++) {
if (strcasecmp(text, bestSoFar) <= 0 || !bestSoFar[0]) { BPose *pose = fPoseList->ItemAt(i);
strcpy(bestSoFar, text); float score = -1;
if (ViewMode() == kListMode) {
ModelNodeLazyOpener modelOpener(pose->TargetModel());
BTextWidget *widget = pose->WidgetFor(column, this, modelOpener);
const char *text = NULL;
if (widget != NULL)
text = widget->Text(this);
if (text != NULL) {
score = ComputeTypeAheadScore(text, sMatchString,
matchLength);
}
} else {
score = ComputeTypeAheadScore(pose->TargetModel()->Name(),
sMatchString, matchLength);
}
if (score > bestScore) {
poseToSelect = pose; poseToSelect = pose;
bestScore = score;
*index = i; *index = i;
} }
if (score == kExactMatchScore)
break;
}
// TODO: we might want to change this to make it always work
// over all columns, but this would require some more changes
// to how Tracker represents data (for example we could filter
// the results out).
if (bestScore > 0 || ViewMode() != kListMode)
break;
} }
return poseToSelect; return poseToSelect;
@@ -6339,7 +6356,7 @@ BPoseView::WasClickInPath(const BPose *pose, int32 index, BPoint mouseLoc) const
if (widget->AttrHash() != AttrHashString(kAttrPath, B_STRING_TYPE)) if (widget->AttrHash() != AttrHashString(kAttrPath, B_STRING_TYPE))
return false; return false;
BEntry entry(widget->Text()); BEntry entry(widget->Text(this));
if (entry.InitCheck() != B_OK) if (entry.InitCheck() != B_OK)
return false; return false;
+4 -6
View File
@@ -92,15 +92,13 @@ BTextWidget::RecalculateText(const BPoseView *view)
const char * const char *
BTextWidget::Text() const BTextWidget::Text(const BPoseView *view) const
{ {
StringAttributeText *textAttribute = dynamic_cast<StringAttributeText *>(fText); StringAttributeText *textAttribute = dynamic_cast<StringAttributeText *>(fText);
if (textAttribute == NULL)
ASSERT(textAttribute); return NULL;
if (!textAttribute)
return "";
return textAttribute->Value(); return textAttribute->ValueAsText(view);
} }
+1 -1
View File
@@ -85,7 +85,7 @@ public:
bool IsActive() const; bool IsActive() const;
void SetActive(bool); void SetActive(bool);
const char *Text() const; const char *Text(const BPoseView *view) const;
// returns the untruncated version of the text // returns the untruncated version of the text
float TextWidth(const BPoseView *) const; float TextWidth(const BPoseView *) const;
float PreferredWidth(const BPoseView *) const; float PreferredWidth(const BPoseView *) const;
+73
View File
@@ -80,6 +80,8 @@ static const float kStubToStringSlotX = 5;
namespace BPrivate { namespace BPrivate {
const float kExactMatchScore = INFINITY;
const rgb_color kBlack = {0, 0, 0, 255}; const rgb_color kBlack = {0, 0, 0, 255};
const rgb_color kWhite = {255, 255, 255, 255}; const rgb_color kWhite = {255, 255, 255, 255};
@@ -1583,6 +1585,77 @@ BootedInSafeMode()
} }
float
ComputeTypeAheadScore(const char *text, const char *match, size_t matchLength,
bool wordMode)
{
float first = -1;
float second = -1;
float third = -1;
// highest score: exact match
float score = 0;
size_t pos = 0;
for (; pos < matchLength; pos++) {
if (text[pos] == '\0') {
score = 0;
break;
}
if (tolower(text[pos]) != tolower(match[pos]))
break;
score++;
}
if (pos == matchLength) {
// we don't need to look any further
return kExactMatchScore;
}
first = score;
// there was no exact match
// second best: all characters at word beginnings
if (wordMode) {
score = 0;
for (int32 j = 0, k = 0; match[j]; j++) {
while (text[k]
&& tolower(text[k]) != tolower(match[j])) {
k++;
}
if (text[k] == '\0') {
score = 0;
break;
}
bool wordStart = k == 0 || isspace(text[k - 1]);
if (wordStart)
score++;
if (j > 0) {
bool wordEnd = !text[k + 1] || isspace(text[k + 1]);
if (wordEnd)
score += 0.3;
if (match[j - 1] == text[k - 1])
score += 0.7;
}
score += 1.f / (k + 1);
k++;
}
second = score;
}
// acceptable last: exact match inside the string
score = 0;
const char* found = strstr(text + 1, match);
if (found != NULL)
score = 1.f / (found - text);
third = score;
return max_c(first, max_c(second, third));
}
void void
_ThrowOnError(status_t error, const char *DEBUG_ONLY(file), int32 DEBUG_ONLY(line)) _ThrowOnError(status_t error, const char *DEBUG_ONLY(file), int32 DEBUG_ONLY(line))
{ {
+6 -2
View File
@@ -587,7 +587,7 @@ inline void PrintDirToStream(const BDirectory *, const char * = 0) {}
thread_info info; \ thread_info info; \
get_thread_info(find_thread(NULL), &info); \ get_thread_info(find_thread(NULL), &info); \
PrintToLogFile("[t %Ld] \"%s\" (%s:%i) ", system_time(), \ PrintToLogFile("[t %Ld] \"%s\" (%s:%i) ", system_time(), \
info.name, __FILE__, __LINE__); \ info.name, __FILE__, __LINE__); \
PrintToLogFile _ARGS_; \ PrintToLogFile _ARGS_; \
PrintToLogFile("\n"); \ PrintToLogFile("\n"); \
fflush(logFile); \ fflush(logFile); \
@@ -616,6 +616,10 @@ inline int64 SwapInt64(int64 value) { return (int64)B_SWAP_INT64((uint64)value);
inline uint64 SwapUInt64(uint64 value) { return B_SWAP_INT64(value); } inline uint64 SwapUInt64(uint64 value) { return B_SWAP_INT64(value); }
extern const float kExactMatchScore;
float ComputeTypeAheadScore(const char *text, const char *match,
size_t matchLength, bool wordMode = false);
} // namespace BPrivate } // namespace BPrivate
#endif #endif // _UTILITIES_H
+91 -76
View File
@@ -85,7 +85,7 @@ TruncStringBase(BString *result, const char *str, int32 length,
BFont font; BFont font;
view->GetFont(&font); view->GetFont(&font);
font.GetTruncatedStrings(srcstr, 1, truncMode, width, results); font.GetTruncatedStrings(srcstr, 1, truncMode, width, results);
result->UnlockBuffer(); result->UnlockBuffer();
} }
@@ -131,7 +131,7 @@ WidgetAttributeText::NewWidgetText(const Model *model,
else if (strcmp(attrName, kAttrOriginalPath) == 0) else if (strcmp(attrName, kAttrOriginalPath) == 0)
return new OriginalPathAttributeText(model, column); return new OriginalPathAttributeText(model, column);
return new GenericAttributeText(model, column); return new GenericAttributeText(model, column);
} }
@@ -167,7 +167,7 @@ bool
WidgetAttributeText::CheckViewChanged(const BPoseView *view) WidgetAttributeText::CheckViewChanged(const BPoseView *view)
{ {
BString newText; BString newText;
FitValue(&newText, view); FitValue(&newText, view);
if (newText == fText) if (newText == fText)
return false; return false;
@@ -288,7 +288,7 @@ TimeFormat(BString &string, int32 index, FormatSeparator separator,
BString clockString; BString clockString;
BString dateString; BString dateString;
if (index <= 1) if (index <= 1)
if (clockIs24Hour) if (clockIs24Hour)
clockString = "%H:%M:%S"; clockString = "%H:%M:%S";
@@ -319,7 +319,7 @@ TimeFormat(BString &string, int32 index, FormatSeparator separator,
if (index == 0) if (index == 0)
dateString.Replace('!', 'B', 1); dateString.Replace('!', 'B', 1);
else else
dateString.Replace('!', 'b', 1); dateString.Replace('!', 'b', 1);
} else { } else {
switch (order) { switch (order) {
case kYMDFormat: case kYMDFormat:
@@ -438,19 +438,19 @@ WidgetAttributeText::CommitEditedText(BTextView *)
} }
status_t status_t
WidgetAttributeText::AttrAsString(const Model *model, BString *result, WidgetAttributeText::AttrAsString(const Model *model, BString *result,
const char *attrName, int32 attrType, const char *attrName, int32 attrType,
float width, BView *view, int64 *resultingValue) float width, BView *view, int64 *resultingValue)
{ {
int64 value; int64 value;
status_t error = model->InitCheck(); status_t error = model->InitCheck();
if (error != B_OK) if (error != B_OK)
return error; return error;
switch (attrType) { switch (attrType) {
case B_TIME_TYPE: case B_TIME_TYPE:
if (strcmp(attrName, kAttrStatModified) == 0) if (strcmp(attrName, kAttrStatModified) == 0)
value = model->StatBuf()->st_mtime; value = model->StatBuf()->st_mtime;
else if (strcmp(attrName, kAttrStatCreated) == 0) else if (strcmp(attrName, kAttrStatCreated) == 0)
@@ -476,34 +476,34 @@ WidgetAttributeText::AttrAsString(const Model *model, BString *result,
TruncateLeaf(&tmp); TruncateLeaf(&tmp);
} else } else
tmp = "-"; tmp = "-";
if (width > 0) if (width > 0)
TruncStringBase(result, tmp.String(), tmp.Length(), view, width); TruncStringBase(result, tmp.String(), tmp.Length(), view, width);
else else
*result = tmp.String(); *result = tmp.String();
return B_OK; return B_OK;
} }
break; break;
case kSizeType: case kSizeType:
// TruncFileSizeBase(result, model->StatBuf()->st_size, view, width); // TruncFileSizeBase(result, model->StatBuf()->st_size, view, width);
return B_OK; return B_OK;
break; break;
default: default:
TRESPASS(); TRESPASS();
// not yet supported // not yet supported
return B_ERROR; return B_ERROR;
}
}
TRESPASS(); TRESPASS();
return B_ERROR; return B_ERROR;
} }
bool bool
WidgetAttributeText::IsEditable() const WidgetAttributeText::IsEditable() const
{ {
return fColumn->Editable() && !BVolume(fModel->StatBuf()->st_dev).IsReadOnly(); return fColumn->Editable() && !BVolume(fModel->StatBuf()->st_dev).IsReadOnly();
@@ -520,15 +520,16 @@ WidgetAttributeText::SetDirty(bool value)
// #pragma mark - // #pragma mark -
StringAttributeText::StringAttributeText(const Model *model, const BColumn *column) StringAttributeText::StringAttributeText(const Model *model,
: WidgetAttributeText(model, column), const BColumn *column)
: WidgetAttributeText(model, column),
fValueDirty(true) fValueDirty(true)
{ {
} }
const char * const char *
StringAttributeText::Value() StringAttributeText::ValueAsText(const BPoseView * /*view*/)
{ {
if (fValueDirty) if (fValueDirty)
ReadValue(&fFullValueText); ReadValue(&fFullValueText);
@@ -545,7 +546,7 @@ StringAttributeText::CheckAttributeChanged()
if (newString == fFullValueText) if (newString == fFullValueText)
return false; return false;
fFullValueText = newString; fFullValueText = newString;
fDirty = true; // have to redo fitted string fDirty = true; // have to redo fitted string
return true; return true;
@@ -573,7 +574,7 @@ StringAttributeText::PreferredWidth(const BPoseView *pose) const
int int
StringAttributeText::Compare(WidgetAttributeText &attr, BPoseView *) StringAttributeText::Compare(WidgetAttributeText &attr, BPoseView *view)
{ {
StringAttributeText *compareTo = StringAttributeText *compareTo =
dynamic_cast<StringAttributeText *>(&attr); dynamic_cast<StringAttributeText *>(&attr);
@@ -582,7 +583,7 @@ StringAttributeText::Compare(WidgetAttributeText &attr, BPoseView *)
if (fValueDirty) if (fValueDirty)
ReadValue(&fFullValueText); ReadValue(&fFullValueText);
return strcasecmp(fFullValueText.String(), compareTo->Value()); return strcasecmp(fFullValueText.String(), compareTo->ValueAsText(view));
} }
@@ -625,7 +626,7 @@ ScalarAttributeText::ScalarAttributeText(const Model *model,
int64 int64
ScalarAttributeText::Value() ScalarAttributeText::Value()
{ {
if (fValueDirty) if (fValueDirty)
fValue = ReadValue(); fValue = ReadValue();
@@ -639,7 +640,7 @@ ScalarAttributeText::CheckAttributeChanged()
int64 newValue = ReadValue(); int64 newValue = ReadValue();
if (newValue == fValue) if (newValue == fValue)
return false; return false;
fValue = newValue; fValue = newValue;
fDirty = true; // have to redo fitted string fDirty = true; // have to redo fitted string
return true; return true;
@@ -757,7 +758,7 @@ NameAttributeText::NameAttributeText(const Model *model, const BColumn *column)
int int
NameAttributeText::Compare(WidgetAttributeText &attr, BPoseView *) NameAttributeText::Compare(WidgetAttributeText &attr, BPoseView *view)
{ {
NameAttributeText *compareTo = dynamic_cast<NameAttributeText *>(&attr); NameAttributeText *compareTo = dynamic_cast<NameAttributeText *>(&attr);
@@ -766,10 +767,10 @@ NameAttributeText::Compare(WidgetAttributeText &attr, BPoseView *)
if (fValueDirty) if (fValueDirty)
ReadValue(&fFullValueText); ReadValue(&fFullValueText);
if (NameAttributeText::sSortFolderNamesFirst) if (NameAttributeText::sSortFolderNamesFirst)
return fModel->CompareFolderNamesFirst(attr.TargetModel()); return fModel->CompareFolderNamesFirst(attr.TargetModel());
return strcasecmp(fFullValueText.String(), compareTo->Value()); return strcasecmp(fFullValueText.String(), compareTo->ValueAsText(view));
} }
@@ -837,7 +838,7 @@ void
NameAttributeText::SetUpEditing(BTextView *textView) NameAttributeText::SetUpEditing(BTextView *textView)
{ {
DisallowFilenameKeys(textView); DisallowFilenameKeys(textView);
textView->SetMaxBytes(B_FILE_NAME_LENGTH); textView->SetMaxBytes(B_FILE_NAME_LENGTH);
textView->SetText(fFullValueText.String(), fFullValueText.Length()); textView->SetText(fFullValueText.String(), fFullValueText.Length());
} }
@@ -906,7 +907,7 @@ bool NameAttributeText::sSortFolderNamesFirst = false;
void void
NameAttributeText::SetSortFolderNamesFirst(bool enabled) NameAttributeText::SetSortFolderNamesFirst(bool enabled)
{ {
NameAttributeText::sSortFolderNamesFirst = enabled; NameAttributeText::sSortFolderNamesFirst = enabled;
} }
@@ -925,7 +926,7 @@ OwnerAttributeText::ReadValue(BString *result)
{ {
uid_t nodeOwner = fModel->StatBuf()->st_uid; uid_t nodeOwner = fModel->StatBuf()->st_uid;
BString user; BString user;
if (nodeOwner == 0) { if (nodeOwner == 0) {
if (getenv("USER") != NULL) if (getenv("USER") != NULL)
user << getenv("USER"); user << getenv("USER");
@@ -933,7 +934,7 @@ OwnerAttributeText::ReadValue(BString *result)
user << "root"; user << "root";
} else } else
user << nodeOwner; user << nodeOwner;
*result = user.String(); *result = user.String();
fValueDirty = false; fValueDirty = false;
} }
@@ -958,7 +959,7 @@ GroupAttributeText::ReadValue(BString *result)
group << "0"; group << "0";
} else } else
group << nodeGroup; group << nodeGroup;
*result = group.String(); *result = group.String();
fValueDirty = false; fValueDirty = false;
} }
@@ -1017,7 +1018,7 @@ SizeAttributeText::ReadValue()
{ {
fValueDirty = false; fValueDirty = false;
// get the size // get the size
if (fModel->IsVolume()) { if (fModel->IsVolume()) {
BVolume volume(fModel->NodeRef()->device); BVolume volume(fModel->NodeRef()->device);
@@ -1122,8 +1123,7 @@ ModificationTimeAttributeText::ReadValue()
GenericAttributeText::GenericAttributeText(const Model *model, GenericAttributeText::GenericAttributeText(const Model *model,
const BColumn *column) const BColumn *column)
: WidgetAttributeText(model, column), : StringAttributeText(model, column)
fValueDirty(true)
{ {
} }
@@ -1133,7 +1133,7 @@ GenericAttributeText::CheckAttributeChanged()
{ {
GenericValueStruct tmpValue = fValue; GenericValueStruct tmpValue = fValue;
BString tmpString(fFullValueText); BString tmpString(fFullValueText);
ReadValue(); ReadValue(&fFullValueText);
// fDirty could already be true, in that case we mustn't set it to // fDirty could already be true, in that case we mustn't set it to
// false, even if the attribute text hasn't changed // false, even if the attribute text hasn't changed
@@ -1153,10 +1153,10 @@ GenericAttributeText::PreferredWidth(const BPoseView *pose) const
void void
GenericAttributeText::ReadValue() GenericAttributeText::ReadValue(BString *result)
{ {
BModelOpener opener(const_cast<Model *>(fModel)); BModelOpener opener(const_cast<Model *>(fModel));
ssize_t length = 0; ssize_t length = 0;
fFullValueText = "-"; fFullValueText = "-";
fValue.int64t = 0; fValue.int64t = 0;
@@ -1179,7 +1179,7 @@ GenericAttributeText::ReadValue()
// didn't read the whole attribute in or it wasn't to // didn't read the whole attribute in or it wasn't to
// begin with // begin with
fFullValueText = buffer; *result = buffer;
fValueIsDefined = true; fValueIsDefined = true;
} }
break; break;
@@ -1270,7 +1270,7 @@ void
GenericAttributeText::FitValue(BString *result, const BPoseView *view) GenericAttributeText::FitValue(BString *result, const BPoseView *view)
{ {
if (fValueDirty) if (fValueDirty)
ReadValue(); ReadValue(&fFullValueText);
fOldWidth = fColumn->Width(); fOldWidth = fColumn->Width();
@@ -1303,11 +1303,11 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
fFullValueText.Length(), view, fOldWidth); fFullValueText.Length(), view, fOldWidth);
fDirty = false; fDirty = false;
return; return;
case B_OFF_T_TYPE: case B_OFF_T_TYPE:
// as a side effect update the fFullValueText to the string representation // as a side effect update the fFullValueText to the string representation
// of value // of value
TruncFileSize(&fFullValueText, fValue.off_tt, view, 100000); TruncFileSize(&fFullValueText, fValue.off_tt, view, 100000);
fTruncatedWidth = TruncFileSize(result, fValue.off_tt, view, fOldWidth); fTruncatedWidth = TruncFileSize(result, fValue.off_tt, view, fOldWidth);
fDirty = false; fDirty = false;
return; return;
@@ -1315,7 +1315,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
case B_TIME_TYPE: case B_TIME_TYPE:
// as a side effect update the fFullValueText to the string representation // as a side effect update the fFullValueText to the string representation
// of value // of value
TruncTime(&fFullValueText, fValue.time_tt, view, 100000); TruncTime(&fFullValueText, fValue.time_tt, view, 100000);
fTruncatedWidth = TruncTime(result, fValue.time_tt, view, fOldWidth); fTruncatedWidth = TruncTime(result, fValue.time_tt, view, fOldWidth);
fDirty = false; fDirty = false;
return; return;
@@ -1323,7 +1323,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
case B_BOOL_TYPE: case B_BOOL_TYPE:
// For now use true/false, would be nice to be able to set // For now use true/false, would be nice to be able to set
// the value text // the value text
sprintf(buffer, "%s", fValue.boolt ? "true" : "false"); sprintf(buffer, "%s", fValue.boolt ? "true" : "false");
fFullValueText = buffer; fFullValueText = buffer;
break; break;
@@ -1337,7 +1337,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
fDirty = false; fDirty = false;
return; return;
} }
sprintf(buffer, "%c", fValue.uint8t); sprintf(buffer, "%c", fValue.uint8t);
fFullValueText = buffer; fFullValueText = buffer;
break; break;
@@ -1381,7 +1381,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
sprintf(buffer, "%Ld", fValue.uint64t); sprintf(buffer, "%Ld", fValue.uint64t);
fFullValueText = buffer; fFullValueText = buffer;
break; break;
case B_FLOAT_TYPE: case B_FLOAT_TYPE:
if (fabs(fValue.floatt) >= 10000 if (fabs(fValue.floatt) >= 10000
|| fabs(fValue.floatt) < 0.01) || fabs(fValue.floatt) < 0.01)
@@ -1392,7 +1392,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
sprintf(buffer, "%.3f", fValue.floatt); sprintf(buffer, "%.3f", fValue.floatt);
fFullValueText = buffer; fFullValueText = buffer;
break; break;
case B_DOUBLE_TYPE: case B_DOUBLE_TYPE:
if (fabs(fValue.doublet) >= 10000 if (fabs(fValue.doublet) >= 10000
|| fabs(fValue.doublet) < 0.01) || fabs(fValue.doublet) < 0.01)
@@ -1403,7 +1403,7 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
sprintf(buffer, "%.3f", fValue.doublet); sprintf(buffer, "%.3f", fValue.doublet);
fFullValueText = buffer; fFullValueText = buffer;
break; break;
default: default:
*result = "-"; *result = "-";
fTruncatedWidth = TruncString(result, fFullValueText.String(), fTruncatedWidth = TruncString(result, fFullValueText.String(),
@@ -1411,11 +1411,25 @@ GenericAttributeText::FitValue(BString *result, const BPoseView *view)
fDirty = false; fDirty = false;
return; return;
} }
fTruncatedWidth = TruncString(result, buffer, (ssize_t)strlen(buffer), view, fOldWidth); fTruncatedWidth = TruncString(result, buffer, (ssize_t)strlen(buffer), view,
fOldWidth);
fDirty = false; fDirty = false;
} }
const char*
GenericAttributeText::ValueAsText(const BPoseView *view)
{
// TODO: redesign this - this is to make sure the value is valid
bool oldDirty = fDirty;
BString result;
FitValue(&result, view);
fDirty = oldDirty;
return fFullValueText.String();
}
int int
GenericAttributeText::Compare(WidgetAttributeText &attr, BPoseView *) GenericAttributeText::Compare(WidgetAttributeText &attr, BPoseView *)
{ {
@@ -1424,14 +1438,15 @@ GenericAttributeText::Compare(WidgetAttributeText &attr, BPoseView *)
ASSERT(compareTo); ASSERT(compareTo);
if (fValueDirty) if (fValueDirty)
ReadValue(); ReadValue(&fFullValueText);
if (compareTo->fValueDirty) if (compareTo->fValueDirty)
compareTo->ReadValue(); compareTo->ReadValue(&compareTo->fFullValueText);
// Sort undefined values last, regardless of the other value: // Sort undefined values last, regardless of the other value:
if (fValueIsDefined == false || compareTo->fValueIsDefined == false) if (fValueIsDefined == false || compareTo->fValueIsDefined == false) {
return fValueIsDefined < compareTo->fValueIsDefined ? return fValueIsDefined < compareTo->fValueIsDefined ?
(fValueIsDefined == compareTo->fValueIsDefined ? 0 : -1) : 1; (fValueIsDefined == compareTo->fValueIsDefined ? 0 : -1) : 1;
}
switch (fColumn->AttrType()) { switch (fColumn->AttrType()) {
case B_STRING_TYPE: case B_STRING_TYPE:
@@ -1441,10 +1456,10 @@ GenericAttributeText::Compare(WidgetAttributeText &attr, BPoseView *)
{ {
char vStr[2] = { static_cast<char>(fValue.uint8t), 0 }; char vStr[2] = { static_cast<char>(fValue.uint8t), 0 };
char cStr[2] = { static_cast<char>(compareTo->fValue.uint8t), 0}; char cStr[2] = { static_cast<char>(compareTo->fValue.uint8t), 0};
BString valueStr(vStr); BString valueStr(vStr);
BString compareToStr(cStr); BString compareToStr(cStr);
return valueStr.ICompare(compareToStr); return valueStr.ICompare(compareToStr);
} }
@@ -1580,7 +1595,7 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
&& strlen(textView->Text()) != 0; && strlen(textView->Text()) != 0;
size = fModel->WriteAttr(columnName, type, 0, &value, sizeof(bool)); size = fModel->WriteAttr(columnName, type, 0, &value, sizeof(bool));
break; break;
} }
case B_CHAR_TYPE: case B_CHAR_TYPE:
@@ -1593,7 +1608,7 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
"Cancel", 0, 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(); "Cancel", 0, 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go();
return false; return false;
} }
size = fModel->WriteAttr(columnName, type, 0, &ch, sizeof(char)); size = fModel->WriteAttr(columnName, type, 0, &ch, sizeof(char));
break; break;
} }
@@ -1611,7 +1626,7 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
return fValueIsDefined; return fValueIsDefined;
break; break;
} }
case B_DOUBLE_TYPE: case B_DOUBLE_TYPE:
{ {
double doubleVal; double doubleVal;
@@ -1625,7 +1640,7 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
return fValueIsDefined; return fValueIsDefined;
break; break;
} }
case B_TIME_TYPE: case B_TIME_TYPE:
case B_OFF_T_TYPE: case B_OFF_T_TYPE:
case B_UINT64_TYPE: case B_UINT64_TYPE:
@@ -1639,48 +1654,48 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
{ {
GenericValueStruct tmp; GenericValueStruct tmp;
size_t scalarSize = 0; size_t scalarSize = 0;
switch (type) { switch (type) {
case B_TIME_TYPE: case B_TIME_TYPE:
tmp.time_tt = parsedate(textView->Text(), time(0)); tmp.time_tt = parsedate(textView->Text(), time(0));
scalarSize = sizeof(time_t); scalarSize = sizeof(time_t);
break; break;
// do some size independent conversion on builtin types // do some size independent conversion on builtin types
case B_OFF_T_TYPE: case B_OFF_T_TYPE:
tmp.off_tt = StringToScalar(textView->Text()); tmp.off_tt = StringToScalar(textView->Text());
scalarSize = sizeof(off_t); scalarSize = sizeof(off_t);
break; break;
case B_UINT64_TYPE: case B_UINT64_TYPE:
case B_INT64_TYPE: case B_INT64_TYPE:
tmp.int64t = StringToScalar(textView->Text()); tmp.int64t = StringToScalar(textView->Text());
scalarSize = sizeof(int64); scalarSize = sizeof(int64);
break; break;
case B_UINT32_TYPE: case B_UINT32_TYPE:
case B_INT32_TYPE: case B_INT32_TYPE:
tmp.int32t = (int32)StringToScalar(textView->Text()); tmp.int32t = (int32)StringToScalar(textView->Text());
scalarSize = sizeof(int32); scalarSize = sizeof(int32);
break; break;
case B_UINT16_TYPE: case B_UINT16_TYPE:
case B_INT16_TYPE: case B_INT16_TYPE:
tmp.int16t = (int16)StringToScalar(textView->Text()); tmp.int16t = (int16)StringToScalar(textView->Text());
scalarSize = sizeof(int16); scalarSize = sizeof(int16);
break; break;
case B_UINT8_TYPE: case B_UINT8_TYPE:
case B_INT8_TYPE: case B_INT8_TYPE:
tmp.int8t = (int8)StringToScalar(textView->Text()); tmp.int8t = (int8)StringToScalar(textView->Text());
scalarSize = sizeof(int8); scalarSize = sizeof(int8);
break; break;
default: default:
TRESPASS(); TRESPASS();
} }
size = fModel->WriteAttr(columnName, type, 0, &tmp, scalarSize); size = fModel->WriteAttr(columnName, type, 0, &tmp, scalarSize);
break; break;
} }
@@ -1703,14 +1718,14 @@ GenericAttributeText::CommitEditedTextFlavor(BTextView *textView)
OpenWithRelationAttributeText::OpenWithRelationAttributeText(const Model *model, OpenWithRelationAttributeText::OpenWithRelationAttributeText(const Model *model,
const BColumn *column, const BPoseView *view) const BColumn *column, const BPoseView *view)
: ScalarAttributeText(model, column), : ScalarAttributeText(model, column),
fPoseView(view) fPoseView(view)
{ {
} }
int64 int64
OpenWithRelationAttributeText::ReadValue() OpenWithRelationAttributeText::ReadValue()
{ {
fValueDirty = false; fValueDirty = false;
@@ -1726,7 +1741,7 @@ OpenWithRelationAttributeText::ReadValue()
} }
void void
OpenWithRelationAttributeText::FitValue(BString *result, const BPoseView *view) OpenWithRelationAttributeText::FitValue(BString *result, const BPoseView *view)
{ {
if (fValueDirty) if (fValueDirty)
@@ -1747,14 +1762,14 @@ OpenWithRelationAttributeText::FitValue(BString *result, const BPoseView *view)
VersionAttributeText::VersionAttributeText(const Model *model, VersionAttributeText::VersionAttributeText(const Model *model,
const BColumn *column, bool app) const BColumn *column, bool app)
: StringAttributeText(model, column), : StringAttributeText(model, column),
fAppVersion(app) fAppVersion(app)
{ {
} }
void void
VersionAttributeText::ReadValue(BString *result) VersionAttributeText::ReadValue(BString *result)
{ {
fValueDirty = false; fValueDirty = false;
+11 -8
View File
@@ -140,9 +140,11 @@ WidgetAttributeText::TargetModel() const
class StringAttributeText : public WidgetAttributeText { class StringAttributeText : public WidgetAttributeText {
public: public:
StringAttributeText(const Model *, const BColumn *); StringAttributeText(const Model *, const BColumn *);
const char *Value();
virtual const char *ValueAsText(const BPoseView *view);
// returns the untrucated text that corresponds to the attribute // returns the untrucated text that corresponds to the attribute
// value // value
virtual bool CheckAttributeChanged(); virtual bool CheckAttributeChanged();
virtual float PreferredWidth(const BPoseView *) const; virtual float PreferredWidth(const BPoseView *) const;
@@ -156,6 +158,7 @@ class StringAttributeText : public WidgetAttributeText {
virtual void ReadValue(BString *result) = 0; virtual void ReadValue(BString *result) = 0;
virtual int Compare(WidgetAttributeText &, BPoseView *view); virtual int Compare(WidgetAttributeText &, BPoseView *view);
BString fFullValueText; BString fFullValueText;
bool fValueDirty; bool fValueDirty;
// used for lazy read, managed by ReadValue // used for lazy read, managed by ReadValue
@@ -200,32 +203,32 @@ union GenericValueStruct {
}; };
class GenericAttributeText : public WidgetAttributeText { class GenericAttributeText : public StringAttributeText {
// used for displaying mime extra attributes // used for displaying mime extra attributes
// supports different formats // supports different formats
public: public:
GenericAttributeText(const Model *, const BColumn *); GenericAttributeText(const Model *model, const BColumn *column);
virtual bool CheckAttributeChanged(); virtual bool CheckAttributeChanged();
virtual float PreferredWidth(const BPoseView *) const; virtual float PreferredWidth(const BPoseView *view) const;
virtual int Compare(WidgetAttributeText &, BPoseView *view); virtual int Compare(WidgetAttributeText &, BPoseView *view);
virtual void SetUpEditing(BTextView *); virtual void SetUpEditing(BTextView *);
virtual bool CommitEditedText(BTextView *); virtual bool CommitEditedText(BTextView *);
virtual const char *ValueAsText(const BPoseView *view);
private: private:
virtual bool CommitEditedTextFlavor(BTextView *); virtual bool CommitEditedTextFlavor(BTextView *);
virtual void FitValue(BString *result, const BPoseView *); virtual void FitValue(BString *result, const BPoseView *);
virtual void ReadValue(); virtual void ReadValue(BString *result);
// ToDo: // TODO:
// split this up into a scalar flavor and string flavor // split this up into a scalar flavor and string flavor
// to save memory // to save memory
BString fFullValueText;
GenericValueStruct fValue; GenericValueStruct fValue;
bool fValueDirty;
}; };