2 * Copyright 2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
7 * Stephan Aßmus <superstippi@gmx.de>
9 * Copyright 1999, Be Incorporated. All Rights Reserved.
10 * This file may be used under the terms of the Be Sample Code License.
14 #include "PersonView.h"
20 #include <BitmapStream.h>
24 #include <ControlLook.h>
25 #include <GridLayout.h>
27 #include <MenuField.h>
29 #include <PopUpMenu.h>
31 #include <TranslationUtils.h>
32 #include <Translator.h>
33 #include <VolumeRoster.h>
36 #include "AttributeTextControl.h"
37 #include "PictureView.h"
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "People"
44 PersonView::PersonView(const char* name
, const char* categoryAttribute
,
48 fLastModificationTime(0),
51 fCategoryAttribute(categoryAttribute
),
56 SetFlags(Flags() | B_WILL_DRAW
);
61 file
= new BFile(fRef
, B_READ_ONLY
);
63 // Add picture "field", using ID photo 35mm x 45mm ratio
64 fPictureView
= new PictureView(70, 90, ref
);
66 BGridLayout
* layout
= GridLayout();
68 float spacing
= be_control_look
->DefaultItemSpacing();
69 layout
->SetInsets(spacing
, spacing
, spacing
, spacing
);
71 layout
->AddView(fPictureView
, 0, 0, 1, 5);
72 layout
->ItemAt(0, 0)->SetExplicitAlignment(
73 BAlignment(B_ALIGN_CENTER
, B_ALIGN_TOP
));
76 file
->GetModificationTime(&fLastModificationTime
);
81 PersonView::~PersonView()
87 PersonView::AddAttribute(const char* label
, const char* attribute
)
89 // Check if this attribute has already been added.
90 AttributeTextControl
* control
= NULL
;
91 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
92 if (fControls
.ItemAt(i
)->Attribute() == attribute
) {
97 control
= new AttributeTextControl(label
, attribute
);
98 fControls
.AddItem(control
);
100 BGridLayout
* layout
= GridLayout();
101 int32 row
= fControls
.CountItems();
103 if (fCategoryAttribute
== attribute
) {
104 // Special case the category attribute. The Group popup field will
105 // be added as the label instead.
106 fGroups
= new BPopUpMenu(label
);
107 fGroups
->SetRadioMode(false);
110 BMenuField
* field
= new BMenuField("", "", fGroups
);
111 field
->SetEnabled(true);
112 layout
->AddView(field
, 1, row
);
114 control
->SetLabel("");
115 layout
->AddView(control
, 2, row
);
117 layout
->AddItem(control
->CreateLabelLayoutItem(), 1, row
);
118 layout
->AddItem(control
->CreateTextViewLayoutItem(), 2, row
);
121 SetAttribute(attribute
, true);
126 PersonView::MakeFocus(bool focus
)
128 if (focus
&& fControls
.CountItems() > 0)
129 fControls
.ItemAt(0)->MakeFocus();
131 BView::MakeFocus(focus
);
136 PersonView::MessageReceived(BMessage
* msg
)
145 fPictureView
->Revert();
147 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--)
148 fControls
.ItemAt(i
)->Revert();
152 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
153 BTextView
* text
= fControls
.ItemAt(i
)->TextView();
154 if (text
->IsFocus()) {
155 text
->Select(0, text
->TextLength());
163 const char* name
= NULL
;
164 if (msg
->FindString("group", &name
) == B_OK
)
165 SetAttribute(fCategoryAttribute
, name
, false);
174 PersonView::Draw(BRect updateRect
)
179 // Draw a alert/get info-like strip
180 BRect stripeRect
= Bounds();
181 stripeRect
.right
= GridLayout()->HorizontalSpacing()
182 + fPictureView
->Bounds().Width() / 2;
183 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT
));
184 FillRect(stripeRect
);
189 PersonView::BuildGroupMenu()
195 while ((item
= fGroups
->ItemAt(0)) != NULL
) {
196 fGroups
->RemoveItem(item
);
202 BVolumeRoster volumeRoster
;
204 while (volumeRoster
.GetNextVolume(&volume
) == B_OK
) {
206 query
.SetVolume(&volume
);
209 snprintf(buffer
, sizeof(buffer
), "%s=*", fCategoryAttribute
.String());
210 query
.SetPredicate(buffer
);
214 while (query
.GetNextEntry(&entry
) == B_OK
) {
215 BFile
file(&entry
, B_READ_ONLY
);
218 if (file
.InitCheck() == B_OK
219 && file
.GetAttrInfo(fCategoryAttribute
, &info
) == B_OK
221 if (info
.size
> (off_t
)sizeof(buffer
))
222 info
.size
= sizeof(buffer
);
224 if (file
.ReadAttr(fCategoryAttribute
.String(), B_STRING_TYPE
,
225 0, buffer
, info
.size
) < 0) {
229 const char *text
= buffer
;
231 char* offset
= strstr(text
, ",");
235 if (!fGroups
->FindItem(text
)) {
237 while ((item
= fGroups
->ItemAt(index
)) != NULL
) {
238 if (strcmp(text
, item
->Label()) < 0)
242 BMessage
* message
= new BMessage(M_GROUP_MENU
);
243 message
->AddString("group", text
);
244 fGroups
->AddItem(new BMenuItem(text
, message
), index
);
260 fGroups
->AddItem(item
= new BMenuItem(
261 B_TRANSLATE_CONTEXT("none", "Groups list"),
262 new BMessage(M_GROUP_MENU
)));
263 item
->SetEnabled(false);
266 fGroups
->SetTargetForItems(this);
271 PersonView::CreateFile(const entry_ref
* ref
)
279 PersonView::IsSaved() const
281 if (fPictureView
&& fPictureView
->HasChanged())
284 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
285 if (fControls
.ItemAt(i
)->HasChanged())
296 BFile
file(fRef
, B_READ_WRITE
);
297 if (file
.InitCheck() != B_NO_ERROR
)
302 int32 count
= fControls
.CountItems();
303 for (int32 i
= 0; i
< count
; i
++) {
304 AttributeTextControl
* control
= fControls
.ItemAt(i
);
305 const char* value
= control
->Text();
306 file
.WriteAttr(control
->Attribute().String(), B_STRING_TYPE
, 0,
307 value
, strlen(value
) + 1);
311 // Write the picture, if any, in the person file content
313 // Trim any previous content
314 file
.Seek(0, SEEK_SET
);
317 BBitmap
* picture
= fPictureView
->Bitmap();
319 BBitmapStream
stream(picture
);
320 // Detach *our* bitmap from stream to avoid its deletion
321 // at stream object destruction
322 stream
.DetachBitmap(&picture
);
324 BTranslatorRoster
* roster
= BTranslatorRoster::Default();
325 roster
->Translate(&stream
, NULL
, NULL
, &file
,
326 fPictureView
->SuggestedType(), B_TRANSLATOR_BITMAP
,
327 fPictureView
->SuggestedMIMEType());
331 fPictureView
->Update();
334 file
.GetModificationTime(&fLastModificationTime
);
341 PersonView::AttributeValue(const char* attribute
) const
343 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
344 if (fControls
.ItemAt(i
)->Attribute() == attribute
)
345 return fControls
.ItemAt(i
)->Text();
353 PersonView::SetAttribute(const char* attribute
, bool update
)
360 file
= new(std::nothrow
) BFile(fRef
, B_READ_ONLY
);
362 if (file
!= NULL
&& file
->GetAttrInfo(attribute
, &info
) == B_OK
) {
363 value
= (char*)calloc(info
.size
, 1);
364 file
->ReadAttr(attribute
, B_STRING_TYPE
, 0, value
, info
.size
);
367 SetAttribute(attribute
, value
, update
);
375 PersonView::SetAttribute(const char* attribute
, const char* value
,
381 AttributeTextControl
* control
= NULL
;
382 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
383 if (fControls
.ItemAt(i
)->Attribute() == attribute
) {
384 control
= fControls
.ItemAt(i
);
393 control
->SetText(value
);
396 BTextView
* text
= control
->TextView();
399 text
->GetSelection(&start
, &end
);
403 } else if ((end
= text
->TextLength())) {
404 text
->Select(end
, end
);
407 text
->Select(text
->TextLength(), text
->TextLength());
409 control
->SetText(value
);
417 PersonView::UpdatePicture(const entry_ref
* ref
)
419 if (fPictureView
== NULL
)
425 time_t modificationTime
= 0;
427 entry
.GetModificationTime(&modificationTime
);
429 if (entry
.InitCheck() == B_OK
430 && modificationTime
<= fLastModificationTime
) {
434 fPictureView
->Update(ref
);
439 PersonView::IsTextSelected() const
441 for (int32 i
= fControls
.CountItems() - 1; i
>= 0; i
--) {
442 BTextView
* text
= fControls
.ItemAt(i
)->TextView();
445 text
->GetSelection(&start
, &end
);