6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
36 #include "WidgetAttributeText.h"
43 #include <parsedate.h>
46 #include <AppFileInfo.h>
48 #include <DateFormat.h>
49 #include <DateTimeFormat.h>
52 #include <MessageFormat.h>
55 #include <SupportDefs.h>
58 #include <VolumeRoster.h>
60 #include "Attributes.h"
61 #include "FindPanel.h"
62 #include "FSUndoRedo.h"
65 #include "OpenWithWindow.h"
66 #include "MimeTypes.h"
68 #include "SettingsViews.h"
69 #include "Utilities.h"
70 #include "ViewState.h"
73 #undef B_TRANSLATION_CONTEXT
74 #define B_TRANSLATION_CONTEXT "WidgetAttributeText"
77 const int32 kGenericReadBufferSize
= 1024;
79 const char* kSizeFormats
[] = {
88 bool NameAttributeText::sSortFolderNamesFirst
= false;
89 bool RealNameAttributeText::sSortFolderNamesFirst
= false;
94 TruncFileSizeBase(BString
* outString
, int64 value
, const View
* view
,
97 // ToDo: If slow, replace float divisions with shifts
98 // if fast enough, try fitting more decimal places.
100 // ToDo: Update string_for_size() in libshared to be able to
105 // format file size value
106 if (value
== kUnknownSize
) {
108 return view
->StringWidth("-");
109 } else if (value
< kKBSize
) {
110 static BMessageFormat
format(B_TRANSLATE(
111 "{0, plural, one{# byte} other{# bytes}}"));
112 format
.Format(buffer
, value
);
113 if (view
->StringWidth(buffer
.String()) > width
)
114 buffer
.SetToFormat(B_TRANSLATE("%Ld B"), value
);
118 if (value
>= kTBSize
) {
119 suffix
= B_TRANSLATE("TiB");
120 doubleValue
= (double)value
/ kTBSize
;
121 } else if (value
>= kGBSize
) {
122 suffix
= B_TRANSLATE("GiB");
123 doubleValue
= (double)value
/ kGBSize
;
124 } else if (value
>= kMBSize
) {
125 suffix
= B_TRANSLATE("MiB");
126 doubleValue
= (double)value
/ kMBSize
;
128 ASSERT(value
>= kKBSize
);
129 suffix
= B_TRANSLATE("KiB");
130 doubleValue
= (double)value
/ kKBSize
;
133 for (int32 index
= 0; ; index
++) {
134 if (kSizeFormats
[index
] == 0)
137 buffer
.SetToFormat(kSizeFormats
[index
], doubleValue
, suffix
);
138 // strip off an insignificant zero so we don't get readings
141 for (char* tmp
= const_cast<char*>(buffer
.String()); *tmp
!= '\0';
146 if (period
&& period
[1] && period
[2] == '0')
147 // move the rest of the string over the insignificant zero
148 for (char* tmp
= &period
[2]; *tmp
; tmp
++)
151 float resultWidth
= view
->StringWidth(buffer
);
152 if (resultWidth
<= width
) {
153 *outString
= buffer
.String();
159 return TruncStringBase(outString
, buffer
.String(), buffer
.Length(), view
,
160 width
, (uint32
)B_TRUNCATE_END
);
164 template <class View
>
166 TruncStringBase(BString
* outString
, const char* inString
, int32 length
,
167 const View
* view
, float width
, uint32 truncMode
= B_TRUNCATE_MIDDLE
)
169 // we are using a template version of this call to make sure
170 // the right StringWidth gets picked up for BView x BPoseView
171 // for max speed and flexibility
173 // a standard ellipsis inserting fitting algorithm
174 if (view
->StringWidth(inString
, length
) <= width
)
175 *outString
= inString
;
177 const char* source
[1];
180 source
[0] = inString
;
181 results
[0] = outString
->LockBuffer(length
+ 3);
184 view
->GetFont(&font
);
186 font
.GetTruncatedStrings(source
, 1, truncMode
, width
, results
);
187 outString
->UnlockBuffer();
190 return view
->StringWidth(outString
->String(), outString
->Length());
194 template <class View
>
196 TruncTimeBase(BString
* outString
, int64 value
, const View
* view
, float width
)
198 float resultWidth
= width
+ 1;
200 time_t timeValue
= (time_t)value
;
202 // Find the longest possible format that will fit the available space
204 BDateFormatStyle dateStyle
;
205 BTimeFormatStyle timeStyle
;
207 { B_LONG_DATE_FORMAT
, B_MEDIUM_TIME_FORMAT
},
208 { B_LONG_DATE_FORMAT
, B_SHORT_TIME_FORMAT
},
209 { B_MEDIUM_DATE_FORMAT
, B_SHORT_TIME_FORMAT
},
210 { B_SHORT_DATE_FORMAT
, B_SHORT_TIME_FORMAT
},
214 BDateTimeFormat formatter
;
215 for (unsigned int i
= 0; i
< B_COUNT_OF(formats
); ++i
) {
216 if (formatter
.Format(date
, timeValue
, formats
[i
].dateStyle
,
217 formats
[i
].timeStyle
) == B_OK
) {
218 resultWidth
= view
->StringWidth(date
.String(), date
.Length());
219 if (resultWidth
<= width
) {
220 // Found a format that fits the available space, stop searching
226 // If we couldn't fit the date, try with just the time
227 // TODO we could use only the time for "today" dates
228 if (resultWidth
> width
229 && BDateFormat().Format(date
, timeValue
,
230 B_SHORT_DATE_FORMAT
) == B_OK
) {
231 resultWidth
= view
->StringWidth(date
.String(), date
.Length());
234 if (resultWidth
> width
) {
235 // even the shortest format string didn't do it, insert ellipsis
236 resultWidth
= TruncStringBase(outString
, date
.String(),
237 (ssize_t
)date
.Length(), view
, width
);
245 // #pragma mark - WidgetAttributeText base class
249 WidgetAttributeText::NewWidgetText(const Model
* model
,
250 const BColumn
* column
, const BPoseView
* view
)
252 // call this to make the right WidgetAttributeText type for a
255 const char* attrName
= column
->AttrName();
257 if (strcmp(attrName
, kAttrPath
) == 0)
258 return new PathAttributeText(model
, column
);
260 if (strcmp(attrName
, kAttrMIMEType
) == 0)
261 return new KindAttributeText(model
, column
);
263 if (strcmp(attrName
, kAttrStatName
) == 0)
264 return new NameAttributeText(model
, column
);
266 if (strcmp(attrName
, kAttrRealName
) == 0)
267 return new RealNameAttributeText(model
, column
);
269 if (strcmp(attrName
, kAttrStatSize
) == 0)
270 return new SizeAttributeText(model
, column
);
272 if (strcmp(attrName
, kAttrStatModified
) == 0)
273 return new ModificationTimeAttributeText(model
, column
);
275 if (strcmp(attrName
, kAttrStatCreated
) == 0)
276 return new CreationTimeAttributeText(model
, column
);
278 #ifdef OWNER_GROUP_ATTRIBUTES
279 if (strcmp(attrName
, kAttrStatOwner
) == 0)
280 return new OwnerAttributeText(model
, column
);
282 if (strcmp(attrName
, kAttrStatGroup
) == 0)
283 return new GroupAttributeText(model
, column
);
285 if (strcmp(attrName
, kAttrStatMode
) == 0)
286 return new ModeAttributeText(model
, column
);
288 if (strcmp(attrName
, kAttrOpenWithRelation
) == 0)
289 return new OpenWithRelationAttributeText(model
, column
, view
);
291 if (strcmp(attrName
, kAttrAppVersion
) == 0)
292 return new AppShortVersionAttributeText(model
, column
);
294 if (strcmp(attrName
, kAttrSystemVersion
) == 0)
295 return new SystemShortVersionAttributeText(model
, column
);
297 if (strcmp(attrName
, kAttrOriginalPath
) == 0)
298 return new OriginalPathAttributeText(model
, column
);
300 if (column
->DisplayAs() != NULL
) {
301 if (!strncmp(column
->DisplayAs(), "checkbox", 8))
302 return new CheckboxAttributeText(model
, column
);
304 if (!strncmp(column
->DisplayAs(), "duration", 8))
305 return new DurationAttributeText(model
, column
);
307 if (!strncmp(column
->DisplayAs(), "rating", 6))
308 return new RatingAttributeText(model
, column
);
311 return new GenericAttributeText(model
, column
);
315 WidgetAttributeText::WidgetAttributeText(const Model
* model
,
316 const BColumn
* column
)
318 fModel(const_cast<Model
*>(model
)),
321 fTruncatedWidth(-1.0f
),
323 fValueIsDefined(false)
325 ASSERT(fColumn
!= NULL
);
330 ASSERT(fColumn
->Width() > 0);
334 WidgetAttributeText::~WidgetAttributeText()
340 WidgetAttributeText::FittingText(const BPoseView
* view
)
342 if (fDirty
|| fColumn
->Width() != fOldWidth
|| CheckSettingsChanged()
343 || !fValueIsDefined
) {
344 CheckViewChanged(view
);
348 return fText
.String();
353 WidgetAttributeText::CheckViewChanged(const BPoseView
* view
)
356 FitValue(&newText
, view
);
357 if (newText
== fText
)
366 WidgetAttributeText::CheckSettingsChanged()
373 WidgetAttributeText::TruncString(BString
* outString
, const char* inString
,
374 int32 length
, const BPoseView
* view
, float width
, uint32 truncMode
)
376 return TruncStringBase(outString
, inString
, length
, view
, width
, truncMode
);
381 WidgetAttributeText::TruncFileSize(BString
* outString
, int64 value
,
382 const BPoseView
* view
, float width
)
384 return TruncFileSizeBase(outString
, value
, view
, width
);
389 WidgetAttributeText::TruncTime(BString
* outString
, int64 value
,
390 const BPoseView
* view
, float width
)
392 return TruncTimeBase(outString
, value
, view
, width
);
397 WidgetAttributeText::CurrentWidth() const
399 return fTruncatedWidth
;
404 WidgetAttributeText::Width(const BPoseView
* pose
)
407 return CurrentWidth();
412 WidgetAttributeText::SetUpEditing(BTextView
*)
414 ASSERT(fColumn
->Editable());
419 WidgetAttributeText::CommitEditedText(BTextView
*)
421 // can't do anything here at this point
428 WidgetAttributeText::AttrAsString(const Model
* model
, BString
* outString
,
429 const char* attrName
, int32 attrType
, float width
, BView
* view
,
430 int64
* resultingValue
)
434 status_t error
= model
->InitCheck();
440 if (strcmp(attrName
, kAttrStatModified
) == 0)
441 value
= model
->StatBuf()->st_mtime
;
442 else if (strcmp(attrName
, kAttrStatCreated
) == 0)
443 value
= model
->StatBuf()->st_crtime
;
449 TruncTimeBase(outString
, value
, view
, width
);
451 *resultingValue
= value
;
456 if (strcmp(attrName
, kAttrPath
) == 0) {
457 BEntry
entry(model
->EntryRef());
461 if (entry
.InitCheck() == B_OK
462 && entry
.GetPath(&path
) == B_OK
) {
469 TruncStringBase(outString
, tmp
.String(), tmp
.Length(), view
,
472 *outString
= tmp
.String();
479 // TruncFileSizeBase(outString, model->StatBuf()->st_size, view,
497 WidgetAttributeText::IsEditable() const
499 return fColumn
->Editable()
500 && !BVolume(fModel
->StatBuf()->st_dev
).IsReadOnly();
505 WidgetAttributeText::SetDirty(bool value
)
511 // #pragma mark - StringAttributeText
514 StringAttributeText::StringAttributeText(const Model
* model
,
515 const BColumn
* column
)
517 WidgetAttributeText(model
, column
),
524 StringAttributeText::ValueAsText(const BPoseView
* /*view*/)
527 ReadValue(&fFullValueText
);
529 return fFullValueText
.String();
534 StringAttributeText::CheckAttributeChanged()
537 ReadValue(&newString
);
539 if (newString
== fFullValueText
)
542 fFullValueText
= newString
;
543 fDirty
= true; // have to redo fitted string
549 StringAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
552 ReadValue(&fFullValueText
);
553 fOldWidth
= fColumn
->Width();
555 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
556 fFullValueText
.Length(), view
, fOldWidth
);
562 StringAttributeText::PreferredWidth(const BPoseView
* pose
) const
564 return pose
->StringWidth(fFullValueText
.String());
569 StringAttributeText::Compare(WidgetAttributeText
& attr
, BPoseView
* view
)
571 StringAttributeText
* compareTo
= dynamic_cast<StringAttributeText
*>(&attr
);
572 ThrowOnAssert(compareTo
!= NULL
);
575 ReadValue(&fFullValueText
);
577 return NaturalCompare(fFullValueText
.String(),
578 compareTo
->ValueAsText(view
));
583 StringAttributeText::CommitEditedText(BTextView
* textView
)
585 ASSERT(fColumn
->Editable());
586 const char* text
= textView
->Text();
588 if (fFullValueText
== text
) {
593 if (textView
->TextLength() == 0) {
594 // cannot do an empty name
598 // cause re-truncation
601 if (!CommitEditedTextFlavor(textView
))
604 // update text and width in this widget
605 fFullValueText
= text
;
611 // #pragma mark - ScalarAttributeText
614 ScalarAttributeText::ScalarAttributeText(const Model
* model
,
615 const BColumn
* column
)
617 WidgetAttributeText(model
, column
),
625 ScalarAttributeText::Value()
628 fValue
= ReadValue();
635 ScalarAttributeText::CheckAttributeChanged()
637 int64 newValue
= ReadValue();
638 if (newValue
== fValue
)
643 // have to redo fitted string
650 ScalarAttributeText::PreferredWidth(const BPoseView
* pose
) const
653 widthString
<< fValue
;
654 return pose
->StringWidth(widthString
.String());
659 ScalarAttributeText::Compare(WidgetAttributeText
& attr
, BPoseView
*)
661 ScalarAttributeText
* compareTo
= dynamic_cast<ScalarAttributeText
*>(&attr
);
662 ThrowOnAssert(compareTo
!= NULL
);
665 fValue
= ReadValue();
667 return fValue
>= compareTo
->Value()
668 ? (fValue
== compareTo
->Value() ? 0 : 1) : -1;
672 // #pragma mark - PathAttributeText
675 PathAttributeText::PathAttributeText(const Model
* model
, const BColumn
* column
)
677 StringAttributeText(model
, column
)
683 PathAttributeText::ReadValue(BString
* outString
)
686 BEntry
entry(fModel
->EntryRef());
689 if (entry
.InitCheck() == B_OK
&& entry
.GetPath(&path
) == B_OK
) {
690 *outString
= path
.Path();
691 TruncateLeaf(outString
);
699 // #pragma mark - OriginalPathAttributeText
702 OriginalPathAttributeText::OriginalPathAttributeText(const Model
* model
,
703 const BColumn
* column
)
705 StringAttributeText(model
, column
)
711 OriginalPathAttributeText::ReadValue(BString
* outString
)
713 BEntry
entry(fModel
->EntryRef());
716 // get the original path
717 if (entry
.InitCheck() == B_OK
&& FSGetOriginalPath(&entry
, &path
) == B_OK
)
718 *outString
= path
.Path();
726 // #pragma mark - KindAttributeText
729 KindAttributeText::KindAttributeText(const Model
* model
, const BColumn
* column
)
731 StringAttributeText(model
, column
)
737 KindAttributeText::ReadValue(BString
* outString
)
740 char desc
[B_MIME_TYPE_LENGTH
];
743 if (mime
.SetType(fModel
->MimeType()) != B_OK
)
744 *outString
= B_TRANSLATE("Unknown");
745 else if (mime
.GetShortDescription(desc
) == B_OK
) {
746 // get the short mime type description
749 *outString
= fModel
->MimeType();
755 // #pragma mark - NameAttributeText
758 NameAttributeText::NameAttributeText(const Model
* model
,
759 const BColumn
* column
)
761 StringAttributeText(model
, column
)
767 NameAttributeText::Compare(WidgetAttributeText
& attr
, BPoseView
* view
)
769 NameAttributeText
* compareTo
= dynamic_cast<NameAttributeText
*>(&attr
);
770 ThrowOnAssert(compareTo
!= NULL
);
773 ReadValue(&fFullValueText
);
775 if (NameAttributeText::sSortFolderNamesFirst
)
776 return fModel
->CompareFolderNamesFirst(attr
.TargetModel());
778 return NaturalCompare(fFullValueText
.String(),
779 compareTo
->ValueAsText(view
));
784 NameAttributeText::ReadValue(BString
* outString
)
786 *outString
= fModel
->Name();
793 NameAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
796 ReadValue(&fFullValueText
);
797 fOldWidth
= fColumn
->Width();
798 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
799 fFullValueText
.Length(), view
, fOldWidth
, B_TRUNCATE_END
);
805 NameAttributeText::SetUpEditing(BTextView
* textView
)
807 DisallowFilenameKeys(textView
);
809 textView
->SetMaxBytes(B_FILE_NAME_LENGTH
);
810 textView
->SetText(fFullValueText
.String(), fFullValueText
.Length());
815 NameAttributeText::CommitEditedTextFlavor(BTextView
* textView
)
817 const char* text
= textView
->Text();
819 BEntry
entry(fModel
->EntryRef());
820 if (entry
.InitCheck() != B_OK
)
824 if (entry
.GetParent(&parent
) != B_OK
)
827 bool removeExisting
= false;
828 if (parent
.Contains(text
)) {
829 BAlert
* alert
= new BAlert("",
830 B_TRANSLATE("That name is already taken. "
831 "Please type another one."),
832 B_TRANSLATE("Replace other file"),
834 NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
835 alert
->SetShortcut(0, 'r');
839 removeExisting
= true;
843 // use model-flavor specific virtuals for all of these special
846 if (fModel
->IsVolume()) {
847 BVolume
volume(fModel
->NodeRef()->device
);
848 result
= volume
.InitCheck();
849 if (result
== B_OK
) {
850 RenameVolumeUndo
undo(volume
, text
);
852 result
= volume
.SetName(text
);
857 if (fModel
->IsQuery()) {
858 BModelWriteOpener
opener(fModel
);
859 ASSERT(fModel
->Node());
860 MoreOptionsStruct::SetQueryTemporary(fModel
->Node(), false);
863 RenameUndo
undo(entry
, text
);
865 result
= entry
.Rename(text
, removeExisting
);
870 return result
== B_OK
;
875 NameAttributeText::SetSortFolderNamesFirst(bool enabled
)
877 NameAttributeText::sSortFolderNamesFirst
= enabled
;
882 NameAttributeText::IsEditable() const
884 return StringAttributeText::IsEditable()
885 && !fModel
->HasLocalizedName();
889 // #pragma mark - RealNameAttributeText
892 RealNameAttributeText::RealNameAttributeText(const Model
* model
,
893 const BColumn
* column
)
895 StringAttributeText(model
, column
)
901 RealNameAttributeText::Compare(WidgetAttributeText
& attr
, BPoseView
* view
)
903 RealNameAttributeText
* compareTo
904 = dynamic_cast<RealNameAttributeText
*>(&attr
);
905 ThrowOnAssert(compareTo
!= NULL
);
908 ReadValue(&fFullValueText
);
910 if (RealNameAttributeText::sSortFolderNamesFirst
)
911 return fModel
->CompareFolderNamesFirst(attr
.TargetModel());
913 return NaturalCompare(fFullValueText
.String(),
914 compareTo
->ValueAsText(view
));
919 RealNameAttributeText::ReadValue(BString
* outString
)
921 *outString
= fModel
->EntryRef()->name
;
928 RealNameAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
931 ReadValue(&fFullValueText
);
932 fOldWidth
= fColumn
->Width();
933 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
934 fFullValueText
.Length(), view
, fOldWidth
, B_TRUNCATE_END
);
940 RealNameAttributeText::SetUpEditing(BTextView
* textView
)
942 DisallowFilenameKeys(textView
);
944 textView
->SetMaxBytes(B_FILE_NAME_LENGTH
);
945 textView
->SetText(fFullValueText
.String(), fFullValueText
.Length());
950 RealNameAttributeText::CommitEditedTextFlavor(BTextView
* textView
)
952 const char* text
= textView
->Text();
954 BEntry
entry(fModel
->EntryRef());
955 if (entry
.InitCheck() != B_OK
)
959 if (entry
.GetParent(&parent
) != B_OK
)
962 bool removeExisting
= false;
963 if (parent
.Contains(text
)) {
964 BAlert
* alert
= new BAlert("",
965 B_TRANSLATE("That name is already taken. "
966 "Please type another one."),
967 B_TRANSLATE("Replace other file"),
969 NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
971 alert
->SetShortcut(0, 'r');
976 removeExisting
= true;
980 // use model-flavor specific virtuals for all of these special
983 if (fModel
->IsVolume()) {
984 BVolume
volume(fModel
->NodeRef()->device
);
985 result
= volume
.InitCheck();
986 if (result
== B_OK
) {
987 RenameVolumeUndo
undo(volume
, text
);
989 result
= volume
.SetName(text
);
994 if (fModel
->IsQuery()) {
995 BModelWriteOpener
opener(fModel
);
996 ASSERT(fModel
->Node());
997 MoreOptionsStruct::SetQueryTemporary(fModel
->Node(), false);
1000 RenameUndo
undo(entry
, text
);
1002 result
= entry
.Rename(text
, removeExisting
);
1007 return result
== B_OK
;
1012 RealNameAttributeText::SetSortFolderNamesFirst(bool enabled
)
1014 RealNameAttributeText::sSortFolderNamesFirst
= enabled
;
1018 // #pragma mark - owner/group
1021 #ifdef OWNER_GROUP_ATTRIBUTES
1022 OwnerAttributeText::OwnerAttributeText(const Model
* model
,
1023 const BColumn
* column
)
1025 StringAttributeText(model
, column
)
1031 OwnerAttributeText::ReadValue(BString
* outString
)
1033 uid_t nodeOwner
= fModel
->StatBuf()->st_uid
;
1036 if (nodeOwner
== 0) {
1037 if (getenv("USER") != NULL
)
1038 user
<< getenv("USER");
1043 *outString
= user
.String();
1045 fValueDirty
= false;
1049 GroupAttributeText::GroupAttributeText(const Model
* model
,
1050 const BColumn
* column
)
1052 StringAttributeText(model
, column
)
1058 GroupAttributeText::ReadValue(BString
* outString
)
1060 gid_t nodeGroup
= fModel
->StatBuf()->st_gid
;
1063 if (nodeGroup
== 0) {
1064 if (getenv("GROUP") != NULL
)
1065 group
<< getenv("GROUP");
1070 *outString
= group
.String();
1072 fValueDirty
= false;
1074 #endif // OWNER_GROUP_ATTRIBUTES
1077 // #pragma mark - ModeAttributeText
1080 ModeAttributeText::ModeAttributeText(const Model
* model
,
1081 const BColumn
* column
)
1083 StringAttributeText(model
, column
)
1089 ModeAttributeText::ReadValue(BString
* outString
)
1091 mode_t mode
= fModel
->StatBuf()->st_mode
;
1092 mode_t baseMask
= 00400;
1095 char* scanner
= buffer
;
1099 else if (S_ISLNK(mode
))
1101 else if (S_ISBLK(mode
))
1103 else if (S_ISCHR(mode
))
1108 for (int32 index
= 0; index
< 9; index
++) {
1109 *scanner
++ = (mode
& baseMask
) ? "rwx"[index
% 3] : '-';
1114 *outString
= buffer
;
1116 fValueDirty
= false;
1120 // #pragma mark - SizeAttributeText
1123 SizeAttributeText::SizeAttributeText(const Model
* model
,
1124 const BColumn
* column
)
1126 ScalarAttributeText(model
, column
)
1132 SizeAttributeText::ReadValue()
1134 fValueDirty
= false;
1137 if (fModel
->IsVolume()) {
1138 BVolume
volume(fModel
->NodeRef()->device
);
1140 return volume
.Capacity();
1143 if (fModel
->IsDirectory() || fModel
->IsQuery()
1144 || fModel
->IsQueryTemplate() || fModel
->IsSymLink()
1145 || fModel
->IsVirtualDirectory()) {
1146 return kUnknownSize
;
1149 fValueIsDefined
= true;
1151 return fModel
->StatBuf()->st_size
;
1156 SizeAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
1159 fValue
= ReadValue();
1161 fOldWidth
= fColumn
->Width();
1162 fTruncatedWidth
= TruncFileSize(outString
, fValue
, view
, fOldWidth
);
1168 SizeAttributeText::PreferredWidth(const BPoseView
* pose
) const
1170 if (fValueIsDefined
) {
1171 BString widthString
;
1172 TruncFileSize(&widthString
, fValue
, pose
, 100000);
1173 return pose
->StringWidth(widthString
.String());
1176 return pose
->StringWidth("-");
1180 // #pragma mark - TimeAttributeText
1183 TimeAttributeText::TimeAttributeText(const Model
* model
,
1184 const BColumn
* column
)
1186 ScalarAttributeText(model
, column
),
1187 fLastClockIs24(false),
1188 fLastDateOrder(kDateFormatEnd
),
1189 fLastTimeFormatSeparator(kSeparatorsEnd
)
1195 TimeAttributeText::PreferredWidth(const BPoseView
* pose
) const
1197 BString widthString
;
1198 TruncTimeBase(&widthString
, fValue
, pose
, 100000);
1199 return pose
->StringWidth(widthString
.String());
1204 TimeAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
1207 fValue
= ReadValue();
1209 fOldWidth
= fColumn
->Width();
1210 fTruncatedWidth
= TruncTime(outString
, fValue
, view
, fOldWidth
);
1216 TimeAttributeText::CheckSettingsChanged(void)
1218 // TODO : check against the actual locale settings
1223 // #pragma mark - CreationTimeAttributeText
1226 CreationTimeAttributeText::CreationTimeAttributeText(const Model
* model
,
1227 const BColumn
* column
)
1229 TimeAttributeText(model
, column
)
1235 CreationTimeAttributeText::ReadValue()
1237 fValueDirty
= false;
1238 fValueIsDefined
= true;
1239 return fModel
->StatBuf()->st_crtime
;
1243 // #pragma mark - ModificationTimeAttributeText
1246 ModificationTimeAttributeText::ModificationTimeAttributeText(
1247 const Model
* model
, const BColumn
* column
)
1249 TimeAttributeText(model
, column
)
1255 ModificationTimeAttributeText::ReadValue()
1257 fValueDirty
= false;
1258 fValueIsDefined
= true;
1259 return fModel
->StatBuf()->st_mtime
;
1263 // #pragma mark - GenericAttributeText
1266 GenericAttributeText::GenericAttributeText(const Model
* model
,
1267 const BColumn
* column
)
1269 StringAttributeText(model
, column
)
1275 GenericAttributeText::CheckAttributeChanged()
1277 GenericValueStruct tmpValue
= fValue
;
1278 BString
tmpString(fFullValueText
);
1279 ReadValue(&fFullValueText
);
1281 // fDirty could already be true, in that case we mustn't set it to
1282 // false, even if the attribute text hasn't changed
1283 bool changed
= fValue
.int64t
!= tmpValue
.int64t
1284 || tmpString
!= fFullValueText
;
1293 GenericAttributeText::PreferredWidth(const BPoseView
* pose
) const
1295 return pose
->StringWidth(fFullValueText
.String());
1300 GenericAttributeText::ReadValue(BString
* outString
)
1302 BModelOpener
opener(const_cast<Model
*>(fModel
));
1305 fFullValueText
= "-";
1307 fValueIsDefined
= false;
1308 fValueDirty
= false;
1310 if (!fModel
->Node())
1313 switch (fColumn
->AttrType()) {
1316 char buffer
[kGenericReadBufferSize
];
1317 length
= fModel
->Node()->ReadAttr(fColumn
->AttrName(),
1318 fColumn
->AttrType(), 0, buffer
, kGenericReadBufferSize
- 1);
1321 buffer
[length
] = '\0';
1322 // make sure the buffer is null-terminated even if we
1323 // didn't read the whole attribute in or it wasn't to
1326 *outString
= buffer
;
1327 fValueIsDefined
= true;
1332 case B_SSIZE_T_TYPE
:
1348 // read in the numerical bit representation and attach it
1349 // with a type, depending on the bytes that could be read
1351 GenericValueStruct tmp
;
1352 if (fModel
->Node()->GetAttrInfo(fColumn
->AttrName(), &info
)
1354 if (info
.size
&& info
.size
<= (off_t
)sizeof(int64
)) {
1355 length
= fModel
->Node()->ReadAttr(fColumn
->AttrName(),
1356 fColumn
->AttrType(), 0, &tmp
, (size_t)info
.size
);
1359 // We used tmp as a block of memory, now set the
1362 if (length
== info
.size
) {
1363 if (fColumn
->AttrType() == B_FLOAT_TYPE
1364 || fColumn
->AttrType() == B_DOUBLE_TYPE
) {
1365 // filter out special float/double types
1366 switch (info
.size
) {
1368 fValueIsDefined
= true;
1369 fValue
.floatt
= tmp
.floatt
;
1372 case sizeof(double):
1373 fValueIsDefined
= true;
1374 fValue
.doublet
= tmp
.doublet
;
1382 // handle the standard data types
1383 switch (info
.size
) {
1385 // Takes care of bool too.
1386 fValueIsDefined
= true;
1387 fValue
.int8t
= tmp
.int8t
;
1391 fValueIsDefined
= true;
1392 fValue
.int16t
= tmp
.int16t
;
1396 // Takes care of time_t too.
1397 fValueIsDefined
= true;
1398 fValue
.int32t
= tmp
.int32t
;
1402 // Takes care of off_t too.
1403 fValueIsDefined
= true;
1404 fValue
.int64t
= tmp
.int64t
;
1421 GenericAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
1424 ReadValue(&fFullValueText
);
1426 fOldWidth
= fColumn
->Width();
1428 if (!fValueIsDefined
) {
1430 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1431 fFullValueText
.Length(), view
, fOldWidth
);
1438 switch (fColumn
->AttrType()) {
1440 TruncFileSizeBase(outString
, fValue
.int32t
, view
, fOldWidth
);
1443 case B_SSIZE_T_TYPE
:
1444 if (fValue
.int32t
> 0) {
1445 TruncFileSizeBase(outString
, fValue
.int32t
, view
, fOldWidth
);
1448 sprintf(buffer
, "%s", strerror(fValue
.int32t
));
1449 fFullValueText
= buffer
;
1453 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1454 fFullValueText
.Length(), view
, fOldWidth
);
1459 // As a side effect update the fFullValueText to the string
1460 // representation of value
1461 TruncFileSize(&fFullValueText
, fValue
.off_tt
, view
, 100000);
1462 fTruncatedWidth
= TruncFileSize(outString
, fValue
.off_tt
, view
,
1468 // As a side effect update the fFullValueText to the string
1469 // representation of value
1470 TruncTime(&fFullValueText
, fValue
.time_tt
, view
, 100000);
1471 fTruncatedWidth
= TruncTime(outString
, fValue
.time_tt
, view
,
1477 // For now use true/false, would be nice to be able to set
1480 sprintf(buffer
, "%s", fValue
.boolt
? "true" : "false");
1481 fFullValueText
= buffer
;
1485 // Make sure no non-printable characters are displayed:
1486 if (!isprint(fValue
.uint8t
)) {
1488 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1489 fFullValueText
.Length(), view
, fOldWidth
);
1494 sprintf(buffer
, "%c", fValue
.uint8t
);
1495 fFullValueText
= buffer
;
1499 sprintf(buffer
, "%d", fValue
.int8t
);
1500 fFullValueText
= buffer
;
1504 sprintf(buffer
, "%d", fValue
.uint8t
);
1505 fFullValueText
= buffer
;
1509 sprintf(buffer
, "%d", fValue
.int16t
);
1510 fFullValueText
= buffer
;
1514 sprintf(buffer
, "%d", fValue
.uint16t
);
1515 fFullValueText
= buffer
;
1519 sprintf(buffer
, "%" B_PRId32
, fValue
.int32t
);
1520 fFullValueText
= buffer
;
1524 sprintf(buffer
, "%" B_PRId32
, fValue
.uint32t
);
1525 fFullValueText
= buffer
;
1529 sprintf(buffer
, "%" B_PRId64
, fValue
.int64t
);
1530 fFullValueText
= buffer
;
1534 sprintf(buffer
, "%" B_PRId64
, fValue
.uint64t
);
1535 fFullValueText
= buffer
;
1539 snprintf(buffer
, sizeof(buffer
), "%g", fValue
.floatt
);
1540 fFullValueText
= buffer
;
1544 snprintf(buffer
, sizeof(buffer
), "%g", fValue
.doublet
);
1545 fFullValueText
= buffer
;
1550 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1551 fFullValueText
.Length(), view
, fOldWidth
);
1555 fTruncatedWidth
= TruncString(outString
, buffer
, (ssize_t
)strlen(buffer
),
1562 GenericAttributeText::ValueAsText(const BPoseView
* view
)
1564 // TODO: redesign this - this is to make sure the value is valid
1565 bool oldDirty
= fDirty
;
1567 FitValue(&outString
, view
);
1570 return fFullValueText
.String();
1575 GenericAttributeText::Compare(WidgetAttributeText
& attr
, BPoseView
*)
1577 GenericAttributeText
* compareTo
1578 = dynamic_cast<GenericAttributeText
*>(&attr
);
1579 ThrowOnAssert(compareTo
!= NULL
);
1582 ReadValue(&fFullValueText
);
1584 if (compareTo
->fValueDirty
)
1585 compareTo
->ReadValue(&compareTo
->fFullValueText
);
1587 // sort undefined values last, regardless of the other value
1588 if (!fValueIsDefined
)
1589 return compareTo
->fValueIsDefined
? 1 : 0;
1591 if (!compareTo
->fValueIsDefined
)
1594 switch (fColumn
->AttrType()) {
1596 return fFullValueText
.ICompare(compareTo
->fFullValueText
);
1600 char vStr
[2] = { static_cast<char>(fValue
.uint8t
), 0 };
1601 char cStr
[2] = { static_cast<char>(compareTo
->fValue
.uint8t
), 0};
1603 BString
valueStr(vStr
);
1604 BString
compareToStr(cStr
);
1606 return valueStr
.ICompare(compareToStr
);
1610 return fValue
.floatt
>= compareTo
->fValue
.floatt
?
1611 (fValue
.floatt
== compareTo
->fValue
.floatt
? 0 : 1) : -1;
1614 return fValue
.doublet
>= compareTo
->fValue
.doublet
?
1615 (fValue
.doublet
== compareTo
->fValue
.doublet
? 0 : 1) : -1;
1618 return fValue
.boolt
>= compareTo
->fValue
.boolt
?
1619 (fValue
.boolt
== compareTo
->fValue
.boolt
? 0 : 1) : -1;
1622 return fValue
.uint8t
>= compareTo
->fValue
.uint8t
?
1623 (fValue
.uint8t
== compareTo
->fValue
.uint8t
? 0 : 1) : -1;
1626 return fValue
.int8t
>= compareTo
->fValue
.int8t
?
1627 (fValue
.int8t
== compareTo
->fValue
.int8t
? 0 : 1) : -1;
1630 return fValue
.uint16t
>= compareTo
->fValue
.uint16t
?
1631 (fValue
.uint16t
== compareTo
->fValue
.uint16t
? 0 : 1) : -1;
1634 return fValue
.int16t
>= compareTo
->fValue
.int16t
?
1635 (fValue
.int16t
== compareTo
->fValue
.int16t
? 0 : 1) : -1;
1638 return fValue
.uint32t
>= compareTo
->fValue
.uint32t
?
1639 (fValue
.uint32t
== compareTo
->fValue
.uint32t
? 0 : 1) : -1;
1642 // time_t typedef'd to a long, i.e. a int32
1644 return fValue
.int32t
>= compareTo
->fValue
.int32t
?
1645 (fValue
.int32t
== compareTo
->fValue
.int32t
? 0 : 1) : -1;
1648 // off_t typedef'd to a long long, i.e. a int64
1650 return fValue
.int64t
>= compareTo
->fValue
.int64t
?
1651 (fValue
.int64t
== compareTo
->fValue
.int64t
? 0 : 1) : -1;
1655 return fValue
.uint64t
>= compareTo
->fValue
.uint64t
?
1656 (fValue
.uint64t
== compareTo
->fValue
.uint64t
? 0 : 1) : -1;
1664 GenericAttributeText::CommitEditedText(BTextView
* textView
)
1666 ASSERT(fColumn
->Editable());
1667 const char* text
= textView
->Text();
1669 if (fFullValueText
== text
)
1673 if (!CommitEditedTextFlavor(textView
))
1676 // update text and width in this widget
1677 fFullValueText
= text
;
1678 // cause re-truncation
1687 GenericAttributeText::SetUpEditing(BTextView
* textView
)
1689 textView
->SetMaxBytes(kGenericReadBufferSize
- 1);
1690 textView
->SetText(fFullValueText
.String(), fFullValueText
.Length());
1695 GenericAttributeText::CommitEditedTextFlavor(BTextView
* textView
)
1697 BNode
node(fModel
->EntryRef());
1699 if (node
.InitCheck() != B_OK
)
1702 uint32 type
= fColumn
->AttrType();
1704 if (type
!= B_STRING_TYPE
1705 && type
!= B_UINT64_TYPE
1706 && type
!= B_UINT32_TYPE
1707 && type
!= B_UINT16_TYPE
1708 && type
!= B_UINT8_TYPE
1709 && type
!= B_INT64_TYPE
1710 && type
!= B_INT32_TYPE
1711 && type
!= B_INT16_TYPE
1712 && type
!= B_INT8_TYPE
1713 && type
!= B_OFF_T_TYPE
1714 && type
!= B_TIME_TYPE
1715 && type
!= B_FLOAT_TYPE
1716 && type
!= B_DOUBLE_TYPE
1717 && type
!= B_CHAR_TYPE
1718 && type
!= B_BOOL_TYPE
) {
1719 BAlert
* alert
= new BAlert("",
1720 B_TRANSLATE("Sorry, you cannot edit that attribute."),
1721 B_TRANSLATE("Cancel"),
1722 0, 0, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
1723 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1728 const char* columnName
= fColumn
->AttrName();
1733 size
= fModel
->WriteAttr(columnName
, type
, 0, textView
->Text(),
1734 (size_t)(textView
->TextLength() + 1));
1739 bool value
= strncasecmp(textView
->Text(), "0", 1) != 0
1740 && strncasecmp(textView
->Text(), "off", 2) != 0
1741 && strncasecmp(textView
->Text(), "no", 3) != 0
1742 && strncasecmp(textView
->Text(), "false", 4) != 0
1743 && strlen(textView
->Text()) != 0;
1745 size
= fModel
->WriteAttr(columnName
, type
, 0, &value
, sizeof(bool));
1752 sscanf(textView
->Text(), "%c", &ch
);
1753 //Check if we read the start of a multi-byte glyph:
1755 BAlert
* alert
= new BAlert("",
1756 B_TRANSLATE("Sorry, the 'Character' "
1757 "attribute cannot store a multi-byte glyph."),
1758 B_TRANSLATE("Cancel"),
1759 0, 0, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
1760 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1765 size
= fModel
->WriteAttr(columnName
, type
, 0, &ch
, sizeof(char));
1773 if (sscanf(textView
->Text(), "%f", &floatVal
) == 1) {
1774 fValueIsDefined
= true;
1775 fValue
.floatt
= floatVal
;
1776 size
= fModel
->WriteAttr(columnName
, type
, 0, &floatVal
,
1779 // If the value was already defined, it's on disk.
1781 return fValueIsDefined
;
1790 if (sscanf(textView
->Text(), "%lf", &doubleVal
) == 1) {
1791 fValueIsDefined
= true;
1792 fValue
.doublet
= doubleVal
;
1793 size
= fModel
->WriteAttr(columnName
, type
, 0, &doubleVal
,
1796 // If the value was already defined, it's on disk.
1798 return fValueIsDefined
;
1814 GenericValueStruct tmp
;
1815 size_t scalarSize
= 0;
1819 tmp
.time_tt
= parsedate(textView
->Text(), time(0));
1820 scalarSize
= sizeof(time_t);
1823 // do some size independent conversion on builtin types
1825 tmp
.off_tt
= StringToScalar(textView
->Text());
1826 scalarSize
= sizeof(off_t
);
1831 tmp
.int64t
= StringToScalar(textView
->Text());
1832 scalarSize
= sizeof(int64
);
1837 tmp
.int32t
= (int32
)StringToScalar(textView
->Text());
1838 scalarSize
= sizeof(int32
);
1843 tmp
.int16t
= (int16
)StringToScalar(textView
->Text());
1844 scalarSize
= sizeof(int16
);
1849 tmp
.int8t
= (int8
)StringToScalar(textView
->Text());
1850 scalarSize
= sizeof(int8
);
1857 size
= fModel
->WriteAttr(columnName
, type
, 0, &tmp
, scalarSize
);
1863 BAlert
* alert
= new BAlert("",
1864 B_TRANSLATE("There was an error writing the attribute."),
1865 B_TRANSLATE("Cancel"),
1866 0, 0, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
1867 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
1870 fValueIsDefined
= false;
1874 fValueIsDefined
= true;
1879 // #pragma mark - DurationAttributeText (display as: duration)
1882 DurationAttributeText::DurationAttributeText(const Model
* model
,
1883 const BColumn
* column
)
1885 GenericAttributeText(model
, column
)
1890 // TODO: support editing!
1894 DurationAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
1897 ReadValue(&fFullValueText
);
1899 fOldWidth
= fColumn
->Width();
1902 if (!fValueIsDefined
) {
1904 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1905 fFullValueText
.Length(), view
, fOldWidth
);
1911 switch (fColumn
->AttrType()) {
1913 time
= fValue
.time_tt
* 1000000LL;
1917 time
= fValue
.int8t
* 1000000LL;
1921 time
= fValue
.int16t
* 1000000LL;
1925 time
= fValue
.int32t
* 1000000LL;
1929 time
= fValue
.int64t
;
1933 // TODO: ignores micro seconds for now
1934 int32 seconds
= time
/ 1000000LL;
1936 bool negative
= seconds
< 0;
1940 int32 hours
= seconds
/ 3600;
1941 seconds
-= hours
* 3600;
1942 int32 minutes
= seconds
/ 60;
1943 seconds
= seconds
% 60;
1947 snprintf(buffer
, sizeof(buffer
), "%s%" B_PRId32
":%02" B_PRId32
":%02"
1948 B_PRId32
, negative
? "-" : "", hours
, minutes
, seconds
);
1950 snprintf(buffer
, sizeof(buffer
), "%s%" B_PRId32
":%02" B_PRId32
,
1951 negative
? "-" : "", minutes
, seconds
);
1954 fFullValueText
= buffer
;
1956 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
1957 fFullValueText
.Length(), view
, fOldWidth
);
1961 // #pragma mark - CheckboxAttributeText (display as: checkbox)
1964 CheckboxAttributeText::CheckboxAttributeText(const Model
* model
,
1965 const BColumn
* column
)
1967 GenericAttributeText(model
, column
),
1971 // TODO: better have common data in the column object!
1972 if (const char* separator
= strchr(column
->DisplayAs(), ':')) {
1973 BString
chars(separator
+ 1);
1975 const char* c
= chars
.CharAt(0, &length
);
1976 fOnChar
.SetTo(c
, length
);
1978 c
= chars
.CharAt(1, &length
);
1979 fOffChar
.SetTo(c
, length
);
1986 CheckboxAttributeText::SetUpEditing(BTextView
* view
)
1988 // TODO: support editing for real!
1990 GenericAttributeText::FitValue(&outString
, NULL
);
1991 GenericAttributeText::SetUpEditing(view
);
1996 CheckboxAttributeText::FitValue(BString
* outString
, const BPoseView
* view
)
1999 ReadValue(&fFullValueText
);
2001 fOldWidth
= fColumn
->Width();
2004 if (!fValueIsDefined
) {
2005 *outString
= fOffChar
;
2006 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
2007 fFullValueText
.Length(), view
, fOldWidth
);
2011 bool checked
= false;
2013 switch (fColumn
->AttrType()) {
2015 checked
= fValue
.boolt
;
2020 checked
= fValue
.int8t
!= 0;
2025 checked
= fValue
.int16t
!= 0;
2030 checked
= fValue
.int32t
!= 0;
2034 fFullValueText
= checked
? fOnChar
: fOffChar
;
2036 fTruncatedWidth
= TruncString(outString
, fFullValueText
.String(),
2037 fFullValueText
.Length(), view
, fOldWidth
);
2041 // #pragma mark - RatingAttributeText (display as: rating)
2044 RatingAttributeText::RatingAttributeText(const Model
* model
,
2045 const BColumn
* column
)
2047 GenericAttributeText(model
, column
),
2051 // TODO: support different star counts/max via specifier
2056 RatingAttributeText::SetUpEditing(BTextView
* view
)
2058 // TODO: support editing for real!
2060 GenericAttributeText::FitValue(&outString
, NULL
);
2061 GenericAttributeText::SetUpEditing(view
);
2066 RatingAttributeText::FitValue(BString
* ratingString
, const BPoseView
* view
)
2069 ReadValue(&fFullValueText
);
2071 fOldWidth
= fColumn
->Width();
2075 if (fValueIsDefined
) {
2076 switch (fColumn
->AttrType()) {
2078 rating
= fValue
.int8t
;
2082 rating
= fValue
.int16t
;
2086 rating
= fValue
.int32t
;
2102 int32 steps
= fMax
/ fCount
;
2103 fFullValueText
= "";
2105 for (int32 i
= 0; i
< fCount
; i
++) {
2106 int64 n
= i
* steps
;
2108 fFullValueText
+= "★";
2110 fFullValueText
+= "☆";
2113 fTruncatedWidth
= TruncString(ratingString
, fFullValueText
.String(),
2114 fFullValueText
.Length(), view
, fOldWidth
);
2118 // #pragma mark - OpenWithRelationAttributeText
2121 OpenWithRelationAttributeText::OpenWithRelationAttributeText(const Model
* model
,
2122 const BColumn
* column
, const BPoseView
* view
)
2124 ScalarAttributeText(model
, column
),
2131 OpenWithRelationAttributeText::ReadValue()
2133 fValueDirty
= false;
2135 const OpenWithPoseView
* view
2136 = dynamic_cast<const OpenWithPoseView
*>(fPoseView
);
2138 fValue
= view
->OpenWithRelation(fModel
);
2139 fValueIsDefined
= true;
2147 OpenWithRelationAttributeText::PreferredWidth(const BPoseView
* pose
) const
2149 BString widthString
;
2150 TruncString(&widthString
, fRelationText
.String(), fRelationText
.Length(),
2151 pose
, 500, B_TRUNCATE_END
);
2152 return pose
->StringWidth(widthString
.String());
2157 OpenWithRelationAttributeText::FitValue(BString
* outString
,
2158 const BPoseView
* view
)
2163 ASSERT(view
== fPoseView
);
2164 const OpenWithPoseView
* launchWithView
2165 = dynamic_cast<const OpenWithPoseView
*>(view
);
2166 if (launchWithView
!= NULL
)
2167 launchWithView
->OpenWithRelationDescription(fModel
, &fRelationText
);
2169 fOldWidth
= fColumn
->Width();
2170 fTruncatedWidth
= TruncString(outString
, fRelationText
.String(),
2171 fRelationText
.Length(), view
, fOldWidth
, B_TRUNCATE_END
);
2176 // #pragma mark - VersionAttributeText
2179 VersionAttributeText::VersionAttributeText(const Model
* model
,
2180 const BColumn
* column
, bool app
)
2182 StringAttributeText(model
, column
),
2189 VersionAttributeText::ReadValue(BString
* outString
)
2191 fValueDirty
= false;
2193 BModelOpener
opener(fModel
);
2194 BFile
* file
= dynamic_cast<BFile
*>(fModel
->Node());
2196 BAppFileInfo
info(file
);
2197 version_info version
;
2198 if (info
.InitCheck() == B_OK
2199 && info
.GetVersionInfo(&version
, fAppVersion
2200 ? B_APP_VERSION_KIND
: B_SYSTEM_VERSION_KIND
) == B_OK
) {
2201 *outString
= version
.short_info
;