[haiku-commits] r40381 - haiku/trunk/src/apps/people

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 8 Feb 2011 00:25:16 +0100 (CET)

Author: stippi
Date: 2011-02-08 00:25:16 +0100 (Tue, 08 Feb 2011)
New Revision: 40381
Changeset: http://dev.haiku-os.org/changeset/40381

Added:
   haiku/trunk/src/apps/people/AttributeTextControl.cpp
   haiku/trunk/src/apps/people/AttributeTextControl.h
Removed:
   haiku/trunk/src/apps/people/TTextControl.cpp
   haiku/trunk/src/apps/people/TTextControl.h
Modified:
   haiku/trunk/src/apps/people/Jamfile
   haiku/trunk/src/apps/people/PeopleApp.cpp
   haiku/trunk/src/apps/people/PeopleApp.h
   haiku/trunk/src/apps/people/PeopleView.cpp
   haiku/trunk/src/apps/people/PeopleView.h
   haiku/trunk/src/apps/people/PeopleWindow.cpp
   haiku/trunk/src/apps/people/PeopleWindow.h
   haiku/trunk/src/apps/people/main.cpp
Log:
Reimplemented how People works. The previously hard-coded attribute list
is now only a fallback attribute list which is install in case the Person
MIME type has no attributes at all. Otherwise the GUI is completely driven
by the current Person attributes, as configured (and sorted) by FileTypes.
This has been on my mental TODO list since years. Finally one can add
a "Cell phone" attribute in Filetypes and actually see and edit it in
People. Or a birth day attribute. If I had read the previous code correctly,
it was only due to a bug that People did not remove those any attributes
on every launch.

I've tested this quite a bit, but it wouldn't hurt to test it some more.
The only "regression" I am aware of is that State and Zip code are not
in one line anymore. Perhaps this feature could be reintroduced by looking
at the display width and if two attributes are short, put them in one line...


Copied: haiku/trunk/src/apps/people/AttributeTextControl.cpp (from rev 40352, 
haiku/trunk/src/apps/people/TTextControl.cpp)
===================================================================
--- haiku/trunk/src/apps/people/AttributeTextControl.cpp                        
        (rev 0)
+++ haiku/trunk/src/apps/people/AttributeTextControl.cpp        2011-02-07 
23:25:16 UTC (rev 40381)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2010, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT license.
+ *
+ * Authors:
+ *             Robert Polic
+ *
+ * Copyright 1999, Be Incorporated.   All Rights Reserved.
+ * This file may be used under the terms of the Be Sample Code License.
+ */
+
+
+#include "AttributeTextControl.h"
+
+#include <string.h>
+#include <malloc.h>
+#include <Font.h>
+
+
+AttributeTextControl::AttributeTextControl(const char* label,
+               const char* attribute)
+       :
+       BTextControl(NULL, "", NULL),
+       fAttribute(attribute),
+       fOriginalValue()
+{
+       if (label != NULL && label[0] != 0)
+               SetLabel(BString(label).Append(":"));
+       SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
+}
+
+
+AttributeTextControl::~AttributeTextControl()
+{
+}
+
+
+bool
+AttributeTextControl::HasChanged()
+{
+       return fOriginalValue != Text();
+}
+
+
+void
+AttributeTextControl::Revert()
+{
+       if (HasChanged())
+               SetText(fOriginalValue);
+}
+
+
+void
+AttributeTextControl::Update()
+{
+       fOriginalValue = Text();
+}

Copied: haiku/trunk/src/apps/people/AttributeTextControl.h (from rev 40352, 
haiku/trunk/src/apps/people/TTextControl.h)
===================================================================
--- haiku/trunk/src/apps/people/AttributeTextControl.h                          
(rev 0)
+++ haiku/trunk/src/apps/people/AttributeTextControl.h  2011-02-07 23:25:16 UTC 
(rev 40381)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2005-2010, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT license.
+ *
+ * Authors:
+ *             Robert Polic
+ *
+ * Copyright 1999, Be Incorporated.   All Rights Reserved.
+ * This file may be used under the terms of the Be Sample Code License.
+ */
+#ifndef TEXT_CONTROL_H
+#define TEXT_CONTROL_H
+
+#include <String.h>
+#include <TextControl.h>
+
+
+class AttributeTextControl : public BTextControl {
+public:
+                                                               
AttributeTextControl(const char* label,
+                                                                       const 
char* attribute);
+       virtual                                         ~AttributeTextControl();
+
+                       bool                            HasChanged();
+                       void                            Revert();
+                       void                            Update();
+
+                       const BString&          Attribute() const
+                                                                       { 
return fAttribute; }
+
+private:
+                       BString                         fAttribute;
+                       BString                         fOriginalValue;
+};
+
+#endif // TEXT_CONTROL_H

Modified: haiku/trunk/src/apps/people/Jamfile
===================================================================
--- haiku/trunk/src/apps/people/Jamfile 2011-02-07 23:20:23 UTC (rev 40380)
+++ haiku/trunk/src/apps/people/Jamfile 2011-02-07 23:25:16 UTC (rev 40381)
@@ -1,10 +1,12 @@
 SubDir HAIKU_TOP src apps people ;
 
+UsePrivateHeaders shared ;
+
 Application People : main.cpp
+       AttributeTextControl.cpp
        PeopleApp.cpp
        PeopleView.cpp
        PeopleWindow.cpp 
-       TTextControl.cpp
        : libbe.so libtracker.so $(TARGET_LIBSUPC++) $(HAIKU_LOCALE_LIBS)
        : People.rdef
        ;

Modified: haiku/trunk/src/apps/people/PeopleApp.cpp
===================================================================
--- haiku/trunk/src/apps/people/PeopleApp.cpp   2011-02-07 23:20:23 UTC (rev 
40380)
+++ haiku/trunk/src/apps/people/PeopleApp.cpp   2011-02-07 23:25:16 UTC (rev 
40381)
@@ -1,10 +1,11 @@
 /*
- * Copyright 2005-2009, Haiku, Inc. All rights reserved.
+ * Copyright 2005-2010, Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT license.
  *
  * Authors:
  *             Robert Polic
  *             Axel Dörfler, axeld@xxxxxxxxxxxxxxxx
+ *             Stephan Aßmus <superstippi@xxxxxx>
  *
  * Copyright 1999, Be Incorporated.   All Rights Reserved.
  * This file may be used under the terms of the Be Sample Code License.
@@ -12,6 +13,7 @@
 
 
 #include <Alert.h>
+#include <AutoDeleter.h>
 #include <Bitmap.h>
 #include <Catalog.h>
 #include <Directory.h>
@@ -34,8 +36,18 @@
 #define B_TRANSLATE_CONTEXT "People"
 
 
-struct people_field gFields[] = {
-       { "META:name", 120, B_TRANSLATE("Contact name") },
+struct DefaultAttribute {
+       const char*     attribute;
+       int32           width;
+       const char*     name;
+};
+
+// TODO: Add flags in attribute info message to find these.
+static const char* kNameAttribute = "META:name";
+static const char* kCategoryAttribute = "META:group";
+
+struct DefaultAttribute sDefaultAttributes[] = {
+       { kNameAttribute, 120, B_TRANSLATE("Contact name") },
        { "META:nickname", 120, B_TRANSLATE("Nickname") },
        { "META:company", 120, B_TRANSLATE("Company") },
        { "META:address", 120, B_TRANSLATE("Address") },
@@ -48,16 +60,19 @@
        { "META:fax", 90, B_TRANSLATE("Fax") },
        { "META:email", 120, B_TRANSLATE("E-mail") },
        { "META:url", 120, B_TRANSLATE("URL") },
-       { "META:group", 120, B_TRANSLATE("Group") },
+       { kCategoryAttribute, 120, B_TRANSLATE("Group") },
        { NULL, 0, NULL }
 };
 
 
-TPeopleApp::TPeopleApp(void)
-       : BApplication(APP_SIG),
-       fWindowCount(0)
+TPeopleApp::TPeopleApp()
+       :
+       BApplication(APP_SIG),
+       fWindowCount(0),
+       fAttributes(20, true)
 {
-       fPosition.Set(6, TITLE_BAR_HEIGHT, 6 + WIND_WIDTH, TITLE_BAR_HEIGHT + 
WIND_HEIGHT);
+       fPosition.Set(6, TITLE_BAR_HEIGHT, 6 + WIND_WIDTH,
+               TITLE_BAR_HEIGHT + WIND_HEIGHT);
        BPoint pos = fPosition.LeftTop();
 
        BPath path;
@@ -65,7 +80,7 @@
 
        BDirectory dir(path.Path());
        BEntry entry;
-       if (dir.FindEntry("People_data", &entry) == B_NO_ERROR) {
+       if (dir.FindEntry("People_data", &entry) == B_OK) {
                fPrefs = new BFile(&entry, B_READ_WRITE);
                if (fPrefs->InitCheck() == B_NO_ERROR) {
                        fPrefs->Read(&pos, sizeof(BPoint));
@@ -74,24 +89,16 @@
                }
        } else {
                fPrefs = new BFile();
-               if (dir.CreateFile("People_data", fPrefs) != B_NO_ERROR) {
+               if (dir.CreateFile("People_data", fPrefs) != B_OK) {
                        delete fPrefs;
                        fPrefs = NULL;
                }
        }
 
-       // create indices on all volumes
+       // Read attributes from person mime type. If it does not exist,
+       // or if it contains no attribute definitions, install a "clean"
+       // person mime type from the hard-coded default attributes.
 
-       BVolumeRoster volumeRoster;
-       BVolume volume;
-       while (volumeRoster.GetNextVolume(&volume) == B_OK) {
-               for (int32 i = 0; gFields[i].attribute; i++) {
-                       fs_create_index(volume.Device(), gFields[i].attribute, 
B_STRING_TYPE, 0);
-               }
-       }
-
-       // install person mime type
-
        bool valid = false;
        BMimeType mime;
        mime.SetType(B_PERSON_MIMETYPE);
@@ -99,17 +106,42 @@
        if (mime.IsInstalled()) {
                BMessage info;
                if (mime.GetAttrInfo(&info) == B_NO_ERROR) {
-                       const char *string;
                        int32 index = 0;
-                       while (info.FindString("attr:name", index++, &string) 
== B_OK) {
-                               if (!strcmp(string, gFields[0].attribute)) {
-                                       valid = true;
+                       while (true) {
+                               int32 type;
+                               if (info.FindInt32("attr:type", index, &type) 
!= B_OK)
                                        break;
+                               bool editable;
+                               if (info.FindBool("attr:editable", index, 
&editable) != B_OK)
+                                       break;
+
+                               // TODO: Support other types besides string 
attributes.
+                               if (type != B_STRING_TYPE || !editable)
+                                       break;
+
+                               Attribute* attribute = new Attribute();
+                               ObjectDeleter<Attribute> deleter(attribute);
+                               if (info.FindString("attr:public_name", index,
+                                               &attribute->name) != B_OK) {
+                                       break;
                                }
+                               if (info.FindString("attr:name", index,
+                                               &attribute->attribute) != B_OK) 
{
+                                       break;
+                               }
+
+                               if (!fAttributes.AddItem(attribute))
+                                       break;
+
+                               deleter.Detach();
+                               index++;
                        }
-                       if (!valid)
-                               mime.Delete();
                }
+               if (fAttributes.CountItems() == 0) {
+                       valid = false;
+                       mime.Delete();
+               } else
+                       valid = true;
        }
        if (!valid) {
                mime.Install();
@@ -121,154 +153,185 @@
                mime.SetIcon(kPersonIcon, sizeof(kPersonIcon));
                mime.SetPreferredApp(APP_SIG);
 
-               // add relevant person fields to meta-mime type
-
+               // add default person fields to meta-mime type
                BMessage fields;
-               for (int32 i = 0; gFields[i].attribute; i++) {
-                       fields.AddString("attr:public_name", gFields[i].name);
-                       fields.AddString("attr:name", gFields[i].attribute);
+               for (int32 i = 0; sDefaultAttributes[i].attribute; i++) {
+                       fields.AddString("attr:public_name", 
sDefaultAttributes[i].name);
+                       fields.AddString("attr:name", 
sDefaultAttributes[i].attribute);
                        fields.AddInt32("attr:type", B_STRING_TYPE);
                        fields.AddBool("attr:viewable", true);
                        fields.AddBool("attr:editable", true);
-                       fields.AddInt32("attr:width", gFields[i].width);
+                       fields.AddInt32("attr:width", 
sDefaultAttributes[i].width);
                        fields.AddInt32("attr:alignment", B_ALIGN_LEFT);
                        fields.AddBool("attr:extra", false);
+
+                       // Add the default attribute to the attribute list, too.
+                       Attribute* attribute = new Attribute();
+                       attribute->name = sDefaultAttributes[i].name;
+                       attribute->attribute = sDefaultAttributes[i].attribute;
+                       if (!fAttributes.AddItem(attribute))
+                               delete attribute;
                }
 
                mime.SetAttrInfo(&fields);
        }
+
+       // create indices on all volumes for the found attributes.
+
+       int32 count = fAttributes.CountItems();
+       BVolumeRoster volumeRoster;
+       BVolume volume;
+       while (volumeRoster.GetNextVolume(&volume) == B_OK) {
+               for (int32 i = 0; i < count; i++) {
+                       Attribute* attribute = fAttributes.ItemAt(i);
+                       fs_create_index(volume.Device(), attribute->attribute,
+                               B_STRING_TYPE, 0);
+               }
+       }
+
 }
 
 
-TPeopleApp::~TPeopleApp(void)
+TPeopleApp::~TPeopleApp()
 {
        delete fPrefs;
 }
 
 
 void
-TPeopleApp::AboutRequested(void)
+TPeopleApp::AboutRequested()
 {
-       (new BAlert("", "...by Robert Polic", B_TRANSLATE("OK")))->Go();
+       (new BAlert(B_TRANSLATE("About"), B_UTF8_ELLIPSIS "by Robert Polic",
+               B_TRANSLATE("OK")))->Go();
 }
 
 
 void
-TPeopleApp::ArgvReceived(int32 argc, char **argv)
+TPeopleApp::ArgvReceived(int32 argc, char** argv)
 {
-       TPeopleWindow* window = NULL;
+       BMessage message(B_REFS_RECEIVED);
 
-       for (int32 loop = 1; loop < argc; loop++) {
-               char* arg = argv[loop];
+       for (int32 i = 1; i < argc; i++) {
+               BEntry entry(argv[i]);
+               entry_ref ref;
+               if (entry.Exists() && entry.GetRef(&ref) == B_OK)
+                       message.AddRef("refs", &ref);
+       }
 
-               int32 index;
-               for (index = 0; gFields[index].attribute; index++) {
-                       if (!strncmp(gFields[index].attribute, arg, 
strlen(gFields[index].attribute)))
-                               break;
-               }
-
-               if (gFields[index].attribute != NULL) {
-                       if (!window)
-                               window = NewWindow();
-
-                       while (arg[0] && arg[0] != ' ' && arg[0] != '=')
-                               arg++;
-
-                       if (arg[0]) {
-                               arg++;
-                               window->SetField(index, arg);
-                       }
-               }
-       }
+       RefsReceived(&message);
 }
 
 
 void
-TPeopleApp::MessageReceived(BMessage *msg)
+TPeopleApp::MessageReceived(BMessage* message)
 {
-       switch (msg->what) {
+       switch (message->what) {
                case M_NEW:
                case B_SILENT_RELAUNCH:
-                       NewWindow();
+                       _NewWindow();
                        break;
 
                case M_WINDOW_QUITS:
-                       SavePreferences(msg);
+                       _SavePreferences(message);
                        fWindowCount--;
                        if (fWindowCount < 1)
                                PostMessage(B_QUIT_REQUESTED);
                        break;
 
                default:
-                       BApplication::MessageReceived(msg);
+                       BApplication::MessageReceived(message);
        }
 }
 
 
 void
-TPeopleApp::RefsReceived(BMessage *message)
+TPeopleApp::RefsReceived(BMessage* message)
 {
        int32 index = 0;
-
        while (message->HasRef("refs", index)) {
                entry_ref ref;
                message->FindRef("refs", index++, &ref);
 
-               TPeopleWindow* window = FindWindow(ref);
+               TPeopleWindow* window = _FindWindow(ref);
                if (window != NULL)
                        window->Activate(true);
                else {
                        BFile file(&ref, B_READ_ONLY);
                        if (file.InitCheck() == B_OK)
-                               NewWindow(&ref);
+                               _NewWindow(&ref);
                }
        }
 }
 
 
 void
-TPeopleApp::ReadyToRun(void)
+TPeopleApp::ReadyToRun()
 {
        if (fWindowCount < 1)
-               NewWindow();
+               _NewWindow();
 }
 
 
+// #pragma mark -
+
+
 TPeopleWindow*
-TPeopleApp::NewWindow(entry_ref *ref)
+TPeopleApp::_NewWindow(entry_ref* ref)
 {
-       TPeopleWindow *window;
+       TPeopleWindow* window = new TPeopleWindow(fPosition,
+               B_TRANSLATE("New person"), kNameAttribute,
+               kCategoryAttribute, ref);
 
-       window = new TPeopleWindow(fPosition, B_TRANSLATE("New person"), ref);
+       _AddAttributes(window);
+
        window->Show();
+
        fWindowCount++;
+
+       // Offset the position for the next window which will be opened and
+       // reset it if it would open outside the screen bounds.
        fPosition.OffsetBy(20, 20);
-
-       if (fPosition.bottom > BScreen(B_MAIN_SCREEN_ID).Frame().bottom)
+       BScreen screen(window);
+       if (fPosition.bottom > screen.Frame().bottom)
                fPosition.OffsetTo(fPosition.left, TITLE_BAR_HEIGHT);
-       if (fPosition.right > BScreen(B_MAIN_SCREEN_ID).Frame().right)
+       if (fPosition.right > screen.Frame().right)
                fPosition.OffsetTo(6, fPosition.top);
 
        return window;
 }
 
 
-TPeopleWindow*
-TPeopleApp::FindWindow(entry_ref ref)
+void
+TPeopleApp::_AddAttributes(TPeopleWindow* window) const
 {
-       TPeopleWindow* window;
-       int32 index = 0;
+       int32 count = fAttributes.CountItems();
+       for (int32 i = 0; i < count; i++) {
+               Attribute* attribute = fAttributes.ItemAt(i);
+               const char* label = attribute->name;
+               if (attribute->attribute == kNameAttribute)
+                       label = B_TRANSLATE("Name");
 
-       while ((window = (TPeopleWindow *)WindowAt(index++))) {
-               if (window->FindView("PeopleView") != NULL && window->fRef && 
*window->fRef == ref)
-                       return window;
+               window->AddAttribute(label, attribute->attribute);
        }
+}
+
+
+TPeopleWindow*
+TPeopleApp::_FindWindow(const entry_ref& ref) const
+{
+       for (int32 i = 0; BWindow* window = WindowAt(i); i++) {
+               TPeopleWindow* personWindow = 
dynamic_cast<TPeopleWindow*>(window);
+               if (personWindow == NULL)
+                       continue;
+               if (personWindow->RefersPersonFile(ref))
+                       return personWindow;
+       }
        return NULL;
 }
 
 
 void
-TPeopleApp::SavePreferences(BMessage* message)
+TPeopleApp::_SavePreferences(BMessage* message) const
 {
        BRect frame;
        if (message->FindRect("frame", &frame) != B_OK)
@@ -276,7 +339,7 @@
 
        BPoint leftTop = frame.LeftTop();
 
-       if (fPrefs) {
+       if (fPrefs != NULL) {
                fPrefs->Seek(0, 0);     
                fPrefs->Write(&leftTop, sizeof(BPoint));
        }

Modified: haiku/trunk/src/apps/people/PeopleApp.h
===================================================================
--- haiku/trunk/src/apps/people/PeopleApp.h     2011-02-07 23:20:23 UTC (rev 
40380)
+++ haiku/trunk/src/apps/people/PeopleApp.h     2011-02-07 23:25:16 UTC (rev 
40381)
@@ -1,51 +1,39 @@
-//--------------------------------------------------------------------
-//     
-//     PeopleApp.h
-//
-//     Written by: Robert Polic
-//     
-//--------------------------------------------------------------------
 /*
-       Copyright 1999, Be Incorporated.   All Rights Reserved.
-       This file may be used under the terms of the Be Sample Code License.
-*/
+ * Copyright 2005-2010, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT license.
+ *
+ * Authors:
+ *             Robert Polic
+ *             Stephan Aßmus <superstippi@xxxxxx>
+ *
+ * Copyright 1999, Be Incorporated.   All Rights Reserved.
+ * This file may be used under the terms of the Be Sample Code License.
+ */
+#ifndef PEOPLE_APP_H
+#define PEOPLE_APP_H
 
-#ifndef PEOPLEAPP_H
-#define PEOPLEAPP_H
 
-
 #include <Application.h>
+#include <ObjectList.h>
+#include <String.h>
 
-class BFile;
 
-
 #define        B_PERSON_MIMETYPE       "application/x-person"
 #define APP_SIG                                "application/x-vnd.Be-PEPL"
 
-struct people_field {
-       const char*     attribute;
-       int32           width;
-       const char*     name;
-};
-extern people_field gFields[];
 
-enum messages{
-       M_NEW = 128, M_SAVE, M_SAVE_AS, M_REVERT,
-       M_UNDO, M_SELECT, M_GROUP_MENU, M_WINDOW_QUITS
-};
+class BFile;
 
-enum fields {
-       F_NAME = 0, F_NICKNAME, F_COMPANY, F_ADDRESS,
-       F_CITY, F_STATE, F_ZIP, F_COUNTRY, F_HPHONE,
-       F_WPHONE, F_FAX, F_EMAIL, F_URL, F_GROUP, F_END
+enum {
+       M_NEW                   = 'newp',
+       M_SAVE_AS               = 'svas',
+       M_WINDOW_QUITS  = 'wndq'
 };
 
 class TPeopleWindow;
 
-//====================================================================
-
 class TPeopleApp : public BApplication {
-       public:
+public:
                                                                TPeopleApp();
                virtual                                 ~TPeopleApp();
 
@@ -54,17 +42,26 @@
                virtual void                    MessageReceived(BMessage*);
                virtual void                    RefsReceived(BMessage*);
                virtual void                    ReadyToRun();
-                               TPeopleWindow*  FindWindow(entry_ref);
-                               TPeopleWindow*  NewWindow(entry_ref* = NULL);
 
-                               BFile*                  fPrefs;
+private:
+                               TPeopleWindow*  _FindWindow(const entry_ref&) 
const;
+                               TPeopleWindow*  _NewWindow(entry_ref* = NULL);
+                               void                    
_AddAttributes(TPeopleWindow* window) const;
+                               void                    
_SavePreferences(BMessage* message) const;
 
-       private:
-                               void                    
SavePreferences(BMessage* message);
-
+private:
+                               BFile*                  fPrefs;
                                uint32                  fWindowCount;
                                BRect                   fPosition;
+
+                               struct Attribute {
+                                       BString         attribute;
+                                       int32           width;
+                                       BString         name;
+                               };
+
+                               BObjectList<Attribute> fAttributes;
 };
 
-#endif /* PEOPLEAPP_H */
+#endif // PEOPLE_APP_H
 

Modified: haiku/trunk/src/apps/people/PeopleView.cpp
===================================================================
--- haiku/trunk/src/apps/people/PeopleView.cpp  2011-02-07 23:20:23 UTC (rev 
40380)
+++ haiku/trunk/src/apps/people/PeopleView.cpp  2011-02-07 23:25:16 UTC (rev 
40381)
@@ -1,15 +1,16 @@
-//--------------------------------------------------------------------
-//     
-//     PeopleView.cpp
-//
-//     Written by: Robert Polic
-//     
-//--------------------------------------------------------------------
 /*
-       Copyright 1999, Be Incorporated.   All Rights Reserved.
-       This file may be used under the terms of the Be Sample Code License.
-*/
+ * Copyright 2010, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT license.
+ *
+ * Authors:
+ *             Robert Polic
+ *             Stephan Aßmus <superstippi@xxxxxx>
+ *
+ * Copyright 1999, Be Incorporated.   All Rights Reserved.
+ * This file may be used under the terms of the Be Sample Code License.
+ */
 
+
 #include "PeopleView.h"
 
 #include <stdio.h>
@@ -29,88 +30,77 @@
 #include <VolumeRoster.h>
 #include <Window.h>
 
-#include "TTextControl.h"
+#include "AttributeTextControl.h"
 
 
 #undef B_TRANSLATE_CONTEXT
 #define B_TRANSLATE_CONTEXT "People"
 
 
-TPeopleView::TPeopleView(const char* name, entry_ref *ref)
+TPeopleView::TPeopleView(const char* name, const char* categoryAttribute,
+               const entry_ref *ref)
        :
-       BGridView()
+       BGridView(),
+       fControls(20, false),
+       fCategoryAttribute(categoryAttribute)
 {
        SetName(name);
        if (ref)
                fFile = new BFile(ref, O_RDWR);
        else
                fFile = NULL;
+
+       float spacing = be_control_look->DefaultItemSpacing();
+       GridLayout()->SetInsets(spacing, spacing, spacing, spacing);
 }
 
 
-TPeopleView::~TPeopleView(void)
+TPeopleView::~TPeopleView()
 {
        delete fFile;
 }
 
 
 void
-TPeopleView::AttachedToWindow(void)
+TPeopleView::AddAttribute(const char* label, const char* attribute)
 {
-       BGridLayout* layout = GridLayout();
+       // TODO: We could check if this attribute has already been added.
 
-       int32 row = 0;
-       for (int32 i = 0; gFields[i].attribute; i++, row++) {
-               const char *name = gFields[i].name;
+       AttributeTextControl* control = new AttributeTextControl(label, 
attribute);
+       fControls.AddItem(control);
 
-               if (i == F_NAME)
-                       name = B_TRANSLATE("Name");
+       BGridLayout* layout = GridLayout();
+       int32 row = layout->CountRows();
 
-               char *text = NULL;
-               attr_info info;
-               if (fFile && fFile->GetAttrInfo(gFields[i].attribute, &info) == 
B_OK) {
-                       text = (char *)calloc(info.size, 1);
-                       fFile->ReadAttr(gFields[i].attribute, B_STRING_TYPE,
-                               0, text, info.size);
-               }
+       if (fCategoryAttribute == attribute) {
+               // Special case the category attribute. The Group popup field 
will
+               // be added as the label instead.
+               fGroups = new BPopUpMenu(label);
+               fGroups->SetRadioMode(false);
+               BuildGroupMenu();
 
-               fField[i] = new TTextControl(name, text);
-               free(text);
+               BMenuField* field = new BMenuField("", "", fGroups);
+               field->SetEnabled(true);
+               layout->AddView(field, 0, row);
 
-               int32 labelColumn = 0;
-               int32 textViewColumn = 1;
-               int32 textViewWidth = 3;
-               if (i == F_STATE)
-                       textViewWidth = 1;
-               else if (i == F_ZIP) {
-                       row--;
-                       labelColumn = 2;
-                       textViewColumn = 3;
-                       textViewWidth = 1;
-               }
-               
-               if (i != F_GROUP) {
-                       layout->AddItem(fField[i]->CreateLabelLayoutItem(),
-                               labelColumn, row, 1, 1);
-                       layout->AddItem(fField[i]->CreateTextViewLayoutItem(),
-                               textViewColumn, row, textViewWidth, 1);
-               } else {
-                       fField[i]->SetLabel("");
-                       layout->AddView(fField[i], textViewColumn, row, 
textViewWidth, 1);
-               }
+               control->SetLabel("");
+               layout->AddView(control, 1, row);
+       } else {
+               layout->AddItem(control->CreateLabelLayoutItem(), 0, row);
+               layout->AddItem(control->CreateTextViewLayoutItem(), 1, row);
        }
 
-       fGroups = new BPopUpMenu(gFields[F_GROUP].name);
-       fGroups->SetRadioMode(false);
-       BMenuField *field = new BMenuField("", "", fGroups);
-       field->SetEnabled(true);
-       layout->AddView(field, 0, --row);
+       SetAttribute(attribute, true);
+}
 
-       float spacing = be_control_look->DefaultItemSpacing();
-       layout->SetSpacing(spacing, spacing);
-               // TODO: remove this after #5614 is fixed
-       layout->SetInsets(spacing, spacing, spacing, spacing);
-       fField[F_NAME]->MakeFocus();
+
+void
+TPeopleView::MakeFocus(bool focus)
+{
+       if (focus && fControls.CountItems() > 0)
+               fControls.ItemAt(0)->MakeFocus();
+       else
+               BView::MakeFocus(focus);
 }
 
 
@@ -123,25 +113,34 @@
                        break;
 
                case M_REVERT:
-                       for (int32 loop = 0; loop < F_END; loop++)
-                               fField[loop]->Revert();
+                       for (int32 i = fControls.CountItems() - 1; i >= 0; i--)
+                               fControls.ItemAt(i)->Revert();
                        break;
 
                case M_SELECT:
-                       for (int32 loop = 0; loop < F_END; loop++) {
-                               BTextView* text = fField[loop]->TextView();
+                       for (int32 i = fControls.CountItems() - 1; i >= 0; i--) 
{
+                               BTextView* text = 
fControls.ItemAt(i)->TextView();
                                if (text->IsFocus()) {
                                        text->Select(0, text->TextLength());
                                        break;
                                }
                        }
-                       break;          
+                       break;
+
+               case M_GROUP_MENU:
+               {
+                       const char* name = NULL;
+                       if (msg->FindString("group", &name) == B_OK)
+                               SetAttribute(fCategoryAttribute, name, false);
+                       break;
+               }
+
        }
 }
 
 
 void
-TPeopleView::BuildGroupMenu(void)
+TPeopleView::BuildGroupMenu()
 {
        BMenuItem* item;
        while ((item = fGroups->ItemAt(0)) != NULL) {
@@ -149,7 +148,6 @@
                delete item;
        }
 
-       const char *groupAttribute = gFields[F_GROUP].attribute;
        int32 count = 0;
 
        BVolumeRoster volumeRoster;
@@ -159,7 +157,7 @@
                query.SetVolume(&volume);
 
                char buffer[256];
-               sprintf(buffer, "%s=*", groupAttribute);
+               snprintf(buffer, sizeof(buffer), "%s=*", 
fCategoryAttribute.String());
                query.SetPredicate(buffer);
                query.Fetch();
 
@@ -169,13 +167,15 @@
                        attr_info info;
 
                        if (file.InitCheck() == B_OK
-                               && file.GetAttrInfo(groupAttribute, &info) == 
B_OK
+                               && file.GetAttrInfo(fCategoryAttribute, &info) 
== B_OK
                                && info.size > 1) {
                                if (info.size > sizeof(buffer))
                                        info.size = sizeof(buffer);
 
-                               if (file.ReadAttr(groupAttribute, 
B_STRING_TYPE, 0, buffer, info.size) < B_OK)
+                               if (file.ReadAttr(fCategoryAttribute.String(), 
B_STRING_TYPE,
+                                               0, buffer, info.size) < 0) {
                                        continue;
+                               }
 
                                const char *text = buffer;
                                while (true) {
@@ -207,108 +207,127 @@
                }
        }
 
-       if (!count) {
+       if (count == 0) {
                fGroups->AddItem(item = new BMenuItem(
                        B_TRANSLATE_WITH_CONTEXT("none", "Groups list"), 
                        new BMessage(M_GROUP_MENU)));
                item->SetEnabled(false);
        }
+
+       fGroups->SetTargetForItems(this);
 }
 
 
-bool
-TPeopleView::CheckSave(void)
+void
+TPeopleView::CreateFile(const entry_ref* ref)
 {
-       for (int32 loop = 0; loop < F_END; loop++) {
-               if (fField[loop]->Changed())
-                       return true;
-       }
-
-       return false;
+       delete fFile;
+       fFile = new BFile(ref, B_READ_WRITE);
+       Save();
 }
 
 
-const char*
-TPeopleView::GetField(int32 index)
+bool
+TPeopleView::IsSaved() const
 {
-       if (index < F_END)
-               return fField[index]->Text();
+       for (int32 i = fControls.CountItems() - 1; i >= 0; i--) {
+               if (fControls.ItemAt(i)->HasChanged())
+                       return false;
+       }
 
-       return NULL;
+       return true;
 }
 
 
 void
-TPeopleView::NewFile(entry_ref *ref)
+TPeopleView::Save()
 {
-       delete fFile;
-       fFile = new BFile(ref, B_READ_WRITE);
-       Save();
+       int32 count = fControls.CountItems();
+       for (int32 i = 0; i < count; i++) {
+               AttributeTextControl* control = fControls.ItemAt(i);
+               const char* value = control->Text();
+               fFile->WriteAttr(control->Attribute().String(), B_STRING_TYPE, 
0,
+                       value, strlen(value) + 1);
+               control->Update();
+       }
 }
 
 
-void
-TPeopleView::Save(void)
+const char*
+TPeopleView::AttributeValue(const char* attribute) const
 {
-       for (int32 i = 0; gFields[i].attribute; i++) {
-               const char *text = fField[i]->Text();
-               fFile->WriteAttr(gFields[i].attribute, B_STRING_TYPE, 0, text, 
strlen(text) + 1);
-               fField[i]->Update();
+       for (int32 i = fControls.CountItems() - 1; i >= 0; i--) {
+               if (fControls.ItemAt(i)->Attribute() == attribute)
+                       return fControls.ItemAt(i)->Text();
        }
+       
+       return "";
 }
 
 
 void
-TPeopleView::SetField(int32 index, bool update)
+TPeopleView::SetAttribute(const char* attribute, bool update)
 {
-       char *text = NULL;
+       char* value = NULL;
        attr_info info;
-       if (fFile && fFile->GetAttrInfo(gFields[index].attribute, &info) == 
B_OK) {
-               text = (char *)calloc(info.size, 1);
-               fFile->ReadAttr(gFields[index].attribute, B_STRING_TYPE, 0, 
text,
-                       info.size);
+       if (fFile != NULL && fFile->GetAttrInfo(attribute, &info) == B_OK) {
+               value = (char*)calloc(info.size, 1);
+               fFile->ReadAttr(attribute, B_STRING_TYPE, 0, value, info.size);
        }
 
-       SetField(index, text, update);
-       
-       free(text);
+       SetAttribute(attribute, value, update);
+
+       free(value);
 }
 
 
 void
-TPeopleView::SetField(int32 index, char *data, bool update)
+TPeopleView::SetAttribute(const char* attribute, const char* value,
+       bool update)
 {
-       Window()->Lock();
+       if (!LockLooper())

[... truncated: 719 lines follow ...]

Other related posts: