2 * Copyright 2005-2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
7 * Axel Dörfler, axeld@pinc-software.de
8 * Stephan Aßmus <superstippi@gmx.de>
10 * Copyright 1999, Be Incorporated. All Rights Reserved.
11 * This file may be used under the terms of the Be Sample Code License.
15 #include "PeopleApp.h"
18 #include <AutoDeleter.h>
21 #include <Directory.h>
22 #include <FindDirectory.h>
29 #include <VolumeRoster.h>
31 #include "PersonWindow.h"
32 #include "PersonIcons.h"
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "People"
41 struct DefaultAttribute
{
42 const char* attribute
;
47 // TODO: Add flags in attribute info message to find these.
48 static const char* kNameAttribute
= "META:name";
49 static const char* kCategoryAttribute
= "META:group";
51 struct DefaultAttribute sDefaultAttributes
[] = {
52 { kNameAttribute
, 120, B_TRANSLATE("Contact name") },
53 { "META:nickname", 120, B_TRANSLATE("Nickname") },
54 { "META:company", 120, B_TRANSLATE("Company") },
55 { "META:address", 120, B_TRANSLATE("Address") },
56 { "META:city", 90, B_TRANSLATE("City") },
57 { "META:state", 50, B_TRANSLATE("State") },
58 { "META:zip", 50, B_TRANSLATE("Zip") },
59 { "META:country", 120, B_TRANSLATE("Country") },
60 { "META:hphone", 90, B_TRANSLATE("Home phone") },
61 { "META:wphone", 90, B_TRANSLATE("Work phone") },
62 { "META:fax", 90, B_TRANSLATE("Fax") },
63 { "META:email", 120, B_TRANSLATE("E-mail") },
64 { "META:url", 120, B_TRANSLATE("URL") },
65 { kCategoryAttribute
, 120, B_TRANSLATE("Group") },
70 TPeopleApp::TPeopleApp()
72 BApplication(APP_SIG
),
76 B_TRANSLATE_MARK_SYSTEM_NAME_VOID("People");
78 fPosition
.Set(6, TITLE_BAR_HEIGHT
, 6 + WIND_WIDTH
,
79 TITLE_BAR_HEIGHT
+ WIND_HEIGHT
);
80 BPoint pos
= fPosition
.LeftTop();
83 find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true);
85 BDirectory
dir(path
.Path());
87 if (dir
.FindEntry("People_data", &entry
) == B_OK
) {
88 fPrefs
= new BFile(&entry
, B_READ_WRITE
);
89 if (fPrefs
->InitCheck() == B_NO_ERROR
) {
90 fPrefs
->Read(&pos
, sizeof(BPoint
));
91 if (BScreen(B_MAIN_SCREEN_ID
).Frame().Contains(pos
))
92 fPosition
.OffsetTo(pos
);
96 if (dir
.CreateFile("People_data", fPrefs
) != B_OK
) {
102 // Read attributes from person mime type. If it does not exist,
103 // or if it contains no attribute definitions, install a "clean"
104 // person mime type from the hard-coded default attributes.
107 BMimeType
mime(B_PERSON_MIMETYPE
);
108 if (mime
.IsInstalled()) {
110 if (mime
.GetAttrInfo(&info
) == B_NO_ERROR
) {
114 if (info
.FindInt32("attr:type", index
, &type
) != B_OK
)
117 if (info
.FindBool("attr:editable", index
, &editable
) != B_OK
)
120 // TODO: Support other types besides string attributes.
121 if (type
!= B_STRING_TYPE
|| !editable
)
124 Attribute
* attribute
= new Attribute();
125 ObjectDeleter
<Attribute
> deleter(attribute
);
126 if (info
.FindString("attr:public_name", index
,
127 &attribute
->name
) != B_OK
) {
130 if (info
.FindString("attr:name", index
,
131 &attribute
->attribute
) != B_OK
) {
135 if (!fAttributes
.AddItem(attribute
))
142 if (fAttributes
.CountItems() == 0) {
150 mime
.SetShortDescription(B_TRANSLATE_CONTEXT("Person",
151 "Short mimetype description"));
152 mime
.SetLongDescription(B_TRANSLATE_CONTEXT(
153 "Contact information for a person.",
154 "Long mimetype description"));
155 mime
.SetIcon(kPersonIcon
, sizeof(kPersonIcon
));
156 mime
.SetPreferredApp(APP_SIG
);
158 // add default person fields to meta-mime type
160 for (int32 i
= 0; sDefaultAttributes
[i
].attribute
; i
++) {
161 fields
.AddString("attr:public_name", sDefaultAttributes
[i
].name
);
162 fields
.AddString("attr:name", sDefaultAttributes
[i
].attribute
);
163 fields
.AddInt32("attr:type", B_STRING_TYPE
);
164 fields
.AddBool("attr:viewable", true);
165 fields
.AddBool("attr:editable", true);
166 fields
.AddInt32("attr:width", sDefaultAttributes
[i
].width
);
167 fields
.AddInt32("attr:alignment", B_ALIGN_LEFT
);
168 fields
.AddBool("attr:extra", false);
170 // Add the default attribute to the attribute list, too.
171 Attribute
* attribute
= new Attribute();
172 attribute
->name
= sDefaultAttributes
[i
].name
;
173 attribute
->attribute
= sDefaultAttributes
[i
].attribute
;
174 if (!fAttributes
.AddItem(attribute
))
178 mime
.SetAttrInfo(&fields
);
181 // create indices on all volumes for the found attributes.
183 int32 count
= fAttributes
.CountItems();
184 BVolumeRoster volumeRoster
;
186 while (volumeRoster
.GetNextVolume(&volume
) == B_OK
) {
187 for (int32 i
= 0; i
< count
; i
++) {
188 Attribute
* attribute
= fAttributes
.ItemAt(i
);
189 fs_create_index(volume
.Device(), attribute
->attribute
,
197 TPeopleApp::~TPeopleApp()
204 TPeopleApp::ArgvReceived(int32 argc
, char** argv
)
206 BMessage
message(B_REFS_RECEIVED
);
208 for (int32 i
= 1; i
< argc
; i
++) {
209 BEntry
entry(argv
[i
]);
211 if (entry
.Exists() && entry
.GetRef(&ref
) == B_OK
)
212 message
.AddRef("refs", &ref
);
215 RefsReceived(&message
);
220 TPeopleApp::MessageReceived(BMessage
* message
)
222 switch (message
->what
) {
224 case B_SILENT_RELAUNCH
:
229 _SavePreferences(message
);
231 if (fWindowCount
< 1)
232 PostMessage(B_QUIT_REQUESTED
);
235 case M_CONFIGURE_ATTRIBUTES
:
237 const char* arguments
[] = { "-type", B_PERSON_MIMETYPE
, 0 };
238 status_t ret
= be_roster
->Launch(
239 "application/x-vnd.Haiku-FileTypes",
240 sizeof(arguments
) / sizeof(const char*) - 1,
241 const_cast<char**>(arguments
));
242 if (ret
!= B_OK
&& ret
!= B_ALREADY_RUNNING
) {
243 BString
errorMsg(B_TRANSLATE("Launching the FileTypes "
244 "preflet to configure Person attributes has failed."
246 errorMsg
<< strerror(ret
);
247 BAlert
* alert
= new BAlert(B_TRANSLATE("Error"),
248 errorMsg
.String(), B_TRANSLATE("OK"), NULL
, NULL
,
249 B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
250 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
257 BApplication::MessageReceived(message
);
263 TPeopleApp::RefsReceived(BMessage
* message
)
266 while (message
->HasRef("refs", index
)) {
268 message
->FindRef("refs", index
++, &ref
);
270 PersonWindow
* window
= _FindWindow(ref
);
272 window
->Activate(true);
274 BFile
file(&ref
, B_READ_ONLY
);
275 if (file
.InitCheck() == B_OK
)
283 TPeopleApp::ReadyToRun()
285 if (fWindowCount
< 1)
294 TPeopleApp::_NewWindow(entry_ref
* ref
)
296 PersonWindow
* window
= new PersonWindow(fPosition
,
297 B_TRANSLATE("New person"), kNameAttribute
,
298 kCategoryAttribute
, ref
);
300 _AddAttributes(window
);
306 // Offset the position for the next window which will be opened and
307 // reset it if it would open outside the screen bounds.
308 fPosition
.OffsetBy(20, 20);
309 BScreen
screen(window
);
310 if (fPosition
.bottom
> screen
.Frame().bottom
)
311 fPosition
.OffsetTo(fPosition
.left
, TITLE_BAR_HEIGHT
);
312 if (fPosition
.right
> screen
.Frame().right
)
313 fPosition
.OffsetTo(6, fPosition
.top
);
320 TPeopleApp::_AddAttributes(PersonWindow
* window
) const
322 int32 count
= fAttributes
.CountItems();
323 for (int32 i
= 0; i
< count
; i
++) {
324 Attribute
* attribute
= fAttributes
.ItemAt(i
);
325 const char* label
= attribute
->name
;
326 if (attribute
->attribute
== kNameAttribute
)
327 label
= B_TRANSLATE("Name");
329 window
->AddAttribute(label
, attribute
->attribute
);
335 TPeopleApp::_FindWindow(const entry_ref
& ref
) const
337 for (int32 i
= 0; BWindow
* window
= WindowAt(i
); i
++) {
338 PersonWindow
* personWindow
= dynamic_cast<PersonWindow
*>(window
);
339 if (personWindow
== NULL
)
341 if (personWindow
->RefersPersonFile(ref
))
349 TPeopleApp::_SavePreferences(BMessage
* message
) const
352 if (message
->FindRect("frame", &frame
) != B_OK
)
355 BPoint leftTop
= frame
.LeftTop();
357 if (fPrefs
!= NULL
) {
359 fPrefs
->Write(&leftTop
, sizeof(BPoint
));