1*968ec77eSStephan Aßmus /* 2*968ec77eSStephan Aßmus * Copyright 2010, Haiku, Inc. All rights reserved. 3*968ec77eSStephan Aßmus * Distributed under the terms of the MIT license. 4*968ec77eSStephan Aßmus * 5*968ec77eSStephan Aßmus * Authors: 6*968ec77eSStephan Aßmus * Robert Polic 7*968ec77eSStephan Aßmus * Stephan Aßmus <superstippi@gmx.de> 8*968ec77eSStephan Aßmus * 9*968ec77eSStephan Aßmus * Copyright 1999, Be Incorporated. All Rights Reserved. 10*968ec77eSStephan Aßmus * This file may be used under the terms of the Be Sample Code License. 11*968ec77eSStephan Aßmus */ 12*968ec77eSStephan Aßmus 13*968ec77eSStephan Aßmus 14*968ec77eSStephan Aßmus #include "PersonView.h" 15*968ec77eSStephan Aßmus 16*968ec77eSStephan Aßmus #include <stdio.h> 17*968ec77eSStephan Aßmus #include <stdlib.h> 18*968ec77eSStephan Aßmus #include <string.h> 19*968ec77eSStephan Aßmus 20*968ec77eSStephan Aßmus #include <Catalog.h> 21*968ec77eSStephan Aßmus #include <fs_attr.h> 22*968ec77eSStephan Aßmus #include <Box.h> 23*968ec77eSStephan Aßmus #include <ControlLook.h> 24*968ec77eSStephan Aßmus #include <GridLayout.h> 25*968ec77eSStephan Aßmus #include <Locale.h> 26*968ec77eSStephan Aßmus #include <MenuField.h> 27*968ec77eSStephan Aßmus #include <MenuItem.h> 28*968ec77eSStephan Aßmus #include <PopUpMenu.h> 29*968ec77eSStephan Aßmus #include <Query.h> 30*968ec77eSStephan Aßmus #include <VolumeRoster.h> 31*968ec77eSStephan Aßmus #include <Window.h> 32*968ec77eSStephan Aßmus 33*968ec77eSStephan Aßmus #include "AttributeTextControl.h" 34*968ec77eSStephan Aßmus 35*968ec77eSStephan Aßmus 36*968ec77eSStephan Aßmus #undef B_TRANSLATE_CONTEXT 37*968ec77eSStephan Aßmus #define B_TRANSLATE_CONTEXT "People" 38*968ec77eSStephan Aßmus 39*968ec77eSStephan Aßmus 40*968ec77eSStephan Aßmus PersonView::PersonView(const char* name, const char* categoryAttribute, 41*968ec77eSStephan Aßmus const entry_ref *ref) 42*968ec77eSStephan Aßmus : 43*968ec77eSStephan Aßmus BGridView(), 44*968ec77eSStephan Aßmus fControls(20, false), 45*968ec77eSStephan Aßmus fCategoryAttribute(categoryAttribute) 46*968ec77eSStephan Aßmus { 47*968ec77eSStephan Aßmus SetName(name); 48*968ec77eSStephan Aßmus if (ref) 49*968ec77eSStephan Aßmus fFile = new BFile(ref, O_RDWR); 50*968ec77eSStephan Aßmus else 51*968ec77eSStephan Aßmus fFile = NULL; 52*968ec77eSStephan Aßmus 53*968ec77eSStephan Aßmus float spacing = be_control_look->DefaultItemSpacing(); 54*968ec77eSStephan Aßmus GridLayout()->SetInsets(spacing, spacing, spacing, spacing); 55*968ec77eSStephan Aßmus } 56*968ec77eSStephan Aßmus 57*968ec77eSStephan Aßmus 58*968ec77eSStephan Aßmus PersonView::~PersonView() 59*968ec77eSStephan Aßmus { 60*968ec77eSStephan Aßmus delete fFile; 61*968ec77eSStephan Aßmus } 62*968ec77eSStephan Aßmus 63*968ec77eSStephan Aßmus 64*968ec77eSStephan Aßmus void 65*968ec77eSStephan Aßmus PersonView::AddAttribute(const char* label, const char* attribute) 66*968ec77eSStephan Aßmus { 67*968ec77eSStephan Aßmus // TODO: We could check if this attribute has already been added. 68*968ec77eSStephan Aßmus 69*968ec77eSStephan Aßmus AttributeTextControl* control = new AttributeTextControl(label, attribute); 70*968ec77eSStephan Aßmus fControls.AddItem(control); 71*968ec77eSStephan Aßmus 72*968ec77eSStephan Aßmus BGridLayout* layout = GridLayout(); 73*968ec77eSStephan Aßmus int32 row = layout->CountRows(); 74*968ec77eSStephan Aßmus 75*968ec77eSStephan Aßmus if (fCategoryAttribute == attribute) { 76*968ec77eSStephan Aßmus // Special case the category attribute. The Group popup field will 77*968ec77eSStephan Aßmus // be added as the label instead. 78*968ec77eSStephan Aßmus fGroups = new BPopUpMenu(label); 79*968ec77eSStephan Aßmus fGroups->SetRadioMode(false); 80*968ec77eSStephan Aßmus BuildGroupMenu(); 81*968ec77eSStephan Aßmus 82*968ec77eSStephan Aßmus BMenuField* field = new BMenuField("", "", fGroups); 83*968ec77eSStephan Aßmus field->SetEnabled(true); 84*968ec77eSStephan Aßmus layout->AddView(field, 0, row); 85*968ec77eSStephan Aßmus 86*968ec77eSStephan Aßmus control->SetLabel(""); 87*968ec77eSStephan Aßmus layout->AddView(control, 1, row); 88*968ec77eSStephan Aßmus } else { 89*968ec77eSStephan Aßmus layout->AddItem(control->CreateLabelLayoutItem(), 0, row); 90*968ec77eSStephan Aßmus layout->AddItem(control->CreateTextViewLayoutItem(), 1, row); 91*968ec77eSStephan Aßmus } 92*968ec77eSStephan Aßmus 93*968ec77eSStephan Aßmus SetAttribute(attribute, true); 94*968ec77eSStephan Aßmus } 95*968ec77eSStephan Aßmus 96*968ec77eSStephan Aßmus 97*968ec77eSStephan Aßmus void 98*968ec77eSStephan Aßmus PersonView::MakeFocus(bool focus) 99*968ec77eSStephan Aßmus { 100*968ec77eSStephan Aßmus if (focus && fControls.CountItems() > 0) 101*968ec77eSStephan Aßmus fControls.ItemAt(0)->MakeFocus(); 102*968ec77eSStephan Aßmus else 103*968ec77eSStephan Aßmus BView::MakeFocus(focus); 104*968ec77eSStephan Aßmus } 105*968ec77eSStephan Aßmus 106*968ec77eSStephan Aßmus 107*968ec77eSStephan Aßmus void 108*968ec77eSStephan Aßmus PersonView::MessageReceived(BMessage* msg) 109*968ec77eSStephan Aßmus { 110*968ec77eSStephan Aßmus switch (msg->what) { 111*968ec77eSStephan Aßmus case M_SAVE: 112*968ec77eSStephan Aßmus Save(); 113*968ec77eSStephan Aßmus break; 114*968ec77eSStephan Aßmus 115*968ec77eSStephan Aßmus case M_REVERT: 116*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) 117*968ec77eSStephan Aßmus fControls.ItemAt(i)->Revert(); 118*968ec77eSStephan Aßmus break; 119*968ec77eSStephan Aßmus 120*968ec77eSStephan Aßmus case M_SELECT: 121*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) { 122*968ec77eSStephan Aßmus BTextView* text = fControls.ItemAt(i)->TextView(); 123*968ec77eSStephan Aßmus if (text->IsFocus()) { 124*968ec77eSStephan Aßmus text->Select(0, text->TextLength()); 125*968ec77eSStephan Aßmus break; 126*968ec77eSStephan Aßmus } 127*968ec77eSStephan Aßmus } 128*968ec77eSStephan Aßmus break; 129*968ec77eSStephan Aßmus 130*968ec77eSStephan Aßmus case M_GROUP_MENU: 131*968ec77eSStephan Aßmus { 132*968ec77eSStephan Aßmus const char* name = NULL; 133*968ec77eSStephan Aßmus if (msg->FindString("group", &name) == B_OK) 134*968ec77eSStephan Aßmus SetAttribute(fCategoryAttribute, name, false); 135*968ec77eSStephan Aßmus break; 136*968ec77eSStephan Aßmus } 137*968ec77eSStephan Aßmus 138*968ec77eSStephan Aßmus } 139*968ec77eSStephan Aßmus } 140*968ec77eSStephan Aßmus 141*968ec77eSStephan Aßmus 142*968ec77eSStephan Aßmus void 143*968ec77eSStephan Aßmus PersonView::BuildGroupMenu() 144*968ec77eSStephan Aßmus { 145*968ec77eSStephan Aßmus BMenuItem* item; 146*968ec77eSStephan Aßmus while ((item = fGroups->ItemAt(0)) != NULL) { 147*968ec77eSStephan Aßmus fGroups->RemoveItem(item); 148*968ec77eSStephan Aßmus delete item; 149*968ec77eSStephan Aßmus } 150*968ec77eSStephan Aßmus 151*968ec77eSStephan Aßmus int32 count = 0; 152*968ec77eSStephan Aßmus 153*968ec77eSStephan Aßmus BVolumeRoster volumeRoster; 154*968ec77eSStephan Aßmus BVolume volume; 155*968ec77eSStephan Aßmus while (volumeRoster.GetNextVolume(&volume) == B_OK) { 156*968ec77eSStephan Aßmus BQuery query; 157*968ec77eSStephan Aßmus query.SetVolume(&volume); 158*968ec77eSStephan Aßmus 159*968ec77eSStephan Aßmus char buffer[256]; 160*968ec77eSStephan Aßmus snprintf(buffer, sizeof(buffer), "%s=*", fCategoryAttribute.String()); 161*968ec77eSStephan Aßmus query.SetPredicate(buffer); 162*968ec77eSStephan Aßmus query.Fetch(); 163*968ec77eSStephan Aßmus 164*968ec77eSStephan Aßmus BEntry entry; 165*968ec77eSStephan Aßmus while (query.GetNextEntry(&entry) == B_OK) { 166*968ec77eSStephan Aßmus BFile file(&entry, B_READ_ONLY); 167*968ec77eSStephan Aßmus attr_info info; 168*968ec77eSStephan Aßmus 169*968ec77eSStephan Aßmus if (file.InitCheck() == B_OK 170*968ec77eSStephan Aßmus && file.GetAttrInfo(fCategoryAttribute, &info) == B_OK 171*968ec77eSStephan Aßmus && info.size > 1) { 172*968ec77eSStephan Aßmus if (info.size > sizeof(buffer)) 173*968ec77eSStephan Aßmus info.size = sizeof(buffer); 174*968ec77eSStephan Aßmus 175*968ec77eSStephan Aßmus if (file.ReadAttr(fCategoryAttribute.String(), B_STRING_TYPE, 176*968ec77eSStephan Aßmus 0, buffer, info.size) < 0) { 177*968ec77eSStephan Aßmus continue; 178*968ec77eSStephan Aßmus } 179*968ec77eSStephan Aßmus 180*968ec77eSStephan Aßmus const char *text = buffer; 181*968ec77eSStephan Aßmus while (true) { 182*968ec77eSStephan Aßmus char* offset = strstr(text, ","); 183*968ec77eSStephan Aßmus if (offset != NULL) 184*968ec77eSStephan Aßmus offset[0] = '\0'; 185*968ec77eSStephan Aßmus 186*968ec77eSStephan Aßmus if (!fGroups->FindItem(text)) { 187*968ec77eSStephan Aßmus int32 index = 0; 188*968ec77eSStephan Aßmus while ((item = fGroups->ItemAt(index)) != NULL) { 189*968ec77eSStephan Aßmus if (strcmp(text, item->Label()) < 0) 190*968ec77eSStephan Aßmus break; 191*968ec77eSStephan Aßmus index++; 192*968ec77eSStephan Aßmus } 193*968ec77eSStephan Aßmus BMessage* message = new BMessage(M_GROUP_MENU); 194*968ec77eSStephan Aßmus message->AddString("group", text); 195*968ec77eSStephan Aßmus fGroups->AddItem(new BMenuItem(text, message), index); 196*968ec77eSStephan Aßmus count++; 197*968ec77eSStephan Aßmus } 198*968ec77eSStephan Aßmus if (offset) { 199*968ec77eSStephan Aßmus text = offset + 1; 200*968ec77eSStephan Aßmus while (*text == ' ') 201*968ec77eSStephan Aßmus text++; 202*968ec77eSStephan Aßmus } 203*968ec77eSStephan Aßmus else 204*968ec77eSStephan Aßmus break; 205*968ec77eSStephan Aßmus } 206*968ec77eSStephan Aßmus } 207*968ec77eSStephan Aßmus } 208*968ec77eSStephan Aßmus } 209*968ec77eSStephan Aßmus 210*968ec77eSStephan Aßmus if (count == 0) { 211*968ec77eSStephan Aßmus fGroups->AddItem(item = new BMenuItem( 212*968ec77eSStephan Aßmus B_TRANSLATE_WITH_CONTEXT("none", "Groups list"), 213*968ec77eSStephan Aßmus new BMessage(M_GROUP_MENU))); 214*968ec77eSStephan Aßmus item->SetEnabled(false); 215*968ec77eSStephan Aßmus } 216*968ec77eSStephan Aßmus 217*968ec77eSStephan Aßmus fGroups->SetTargetForItems(this); 218*968ec77eSStephan Aßmus } 219*968ec77eSStephan Aßmus 220*968ec77eSStephan Aßmus 221*968ec77eSStephan Aßmus void 222*968ec77eSStephan Aßmus PersonView::CreateFile(const entry_ref* ref) 223*968ec77eSStephan Aßmus { 224*968ec77eSStephan Aßmus delete fFile; 225*968ec77eSStephan Aßmus fFile = new BFile(ref, B_READ_WRITE); 226*968ec77eSStephan Aßmus Save(); 227*968ec77eSStephan Aßmus } 228*968ec77eSStephan Aßmus 229*968ec77eSStephan Aßmus 230*968ec77eSStephan Aßmus bool 231*968ec77eSStephan Aßmus PersonView::IsSaved() const 232*968ec77eSStephan Aßmus { 233*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) { 234*968ec77eSStephan Aßmus if (fControls.ItemAt(i)->HasChanged()) 235*968ec77eSStephan Aßmus return false; 236*968ec77eSStephan Aßmus } 237*968ec77eSStephan Aßmus 238*968ec77eSStephan Aßmus return true; 239*968ec77eSStephan Aßmus } 240*968ec77eSStephan Aßmus 241*968ec77eSStephan Aßmus 242*968ec77eSStephan Aßmus void 243*968ec77eSStephan Aßmus PersonView::Save() 244*968ec77eSStephan Aßmus { 245*968ec77eSStephan Aßmus int32 count = fControls.CountItems(); 246*968ec77eSStephan Aßmus for (int32 i = 0; i < count; i++) { 247*968ec77eSStephan Aßmus AttributeTextControl* control = fControls.ItemAt(i); 248*968ec77eSStephan Aßmus const char* value = control->Text(); 249*968ec77eSStephan Aßmus fFile->WriteAttr(control->Attribute().String(), B_STRING_TYPE, 0, 250*968ec77eSStephan Aßmus value, strlen(value) + 1); 251*968ec77eSStephan Aßmus control->Update(); 252*968ec77eSStephan Aßmus } 253*968ec77eSStephan Aßmus } 254*968ec77eSStephan Aßmus 255*968ec77eSStephan Aßmus 256*968ec77eSStephan Aßmus const char* 257*968ec77eSStephan Aßmus PersonView::AttributeValue(const char* attribute) const 258*968ec77eSStephan Aßmus { 259*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) { 260*968ec77eSStephan Aßmus if (fControls.ItemAt(i)->Attribute() == attribute) 261*968ec77eSStephan Aßmus return fControls.ItemAt(i)->Text(); 262*968ec77eSStephan Aßmus } 263*968ec77eSStephan Aßmus 264*968ec77eSStephan Aßmus return ""; 265*968ec77eSStephan Aßmus } 266*968ec77eSStephan Aßmus 267*968ec77eSStephan Aßmus 268*968ec77eSStephan Aßmus void 269*968ec77eSStephan Aßmus PersonView::SetAttribute(const char* attribute, bool update) 270*968ec77eSStephan Aßmus { 271*968ec77eSStephan Aßmus char* value = NULL; 272*968ec77eSStephan Aßmus attr_info info; 273*968ec77eSStephan Aßmus if (fFile != NULL && fFile->GetAttrInfo(attribute, &info) == B_OK) { 274*968ec77eSStephan Aßmus value = (char*)calloc(info.size, 1); 275*968ec77eSStephan Aßmus fFile->ReadAttr(attribute, B_STRING_TYPE, 0, value, info.size); 276*968ec77eSStephan Aßmus } 277*968ec77eSStephan Aßmus 278*968ec77eSStephan Aßmus SetAttribute(attribute, value, update); 279*968ec77eSStephan Aßmus 280*968ec77eSStephan Aßmus free(value); 281*968ec77eSStephan Aßmus } 282*968ec77eSStephan Aßmus 283*968ec77eSStephan Aßmus 284*968ec77eSStephan Aßmus void 285*968ec77eSStephan Aßmus PersonView::SetAttribute(const char* attribute, const char* value, 286*968ec77eSStephan Aßmus bool update) 287*968ec77eSStephan Aßmus { 288*968ec77eSStephan Aßmus if (!LockLooper()) 289*968ec77eSStephan Aßmus return; 290*968ec77eSStephan Aßmus 291*968ec77eSStephan Aßmus AttributeTextControl* control = NULL; 292*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) { 293*968ec77eSStephan Aßmus if (fControls.ItemAt(i)->Attribute() == attribute) { 294*968ec77eSStephan Aßmus control = fControls.ItemAt(i); 295*968ec77eSStephan Aßmus break; 296*968ec77eSStephan Aßmus } 297*968ec77eSStephan Aßmus } 298*968ec77eSStephan Aßmus 299*968ec77eSStephan Aßmus if (control == NULL) 300*968ec77eSStephan Aßmus return; 301*968ec77eSStephan Aßmus 302*968ec77eSStephan Aßmus if (update) { 303*968ec77eSStephan Aßmus control->SetText(value); 304*968ec77eSStephan Aßmus control->Update(); 305*968ec77eSStephan Aßmus } else { 306*968ec77eSStephan Aßmus BTextView* text = control->TextView(); 307*968ec77eSStephan Aßmus 308*968ec77eSStephan Aßmus int32 start, end; 309*968ec77eSStephan Aßmus text->GetSelection(&start, &end); 310*968ec77eSStephan Aßmus if (start != end) { 311*968ec77eSStephan Aßmus text->Delete(); 312*968ec77eSStephan Aßmus text->Insert(value); 313*968ec77eSStephan Aßmus } else if ((end = text->TextLength())) { 314*968ec77eSStephan Aßmus text->Select(end, end); 315*968ec77eSStephan Aßmus text->Insert(","); 316*968ec77eSStephan Aßmus text->Insert(value); 317*968ec77eSStephan Aßmus text->Select(text->TextLength(), text->TextLength()); 318*968ec77eSStephan Aßmus } else 319*968ec77eSStephan Aßmus control->SetText(value); 320*968ec77eSStephan Aßmus } 321*968ec77eSStephan Aßmus 322*968ec77eSStephan Aßmus UnlockLooper(); 323*968ec77eSStephan Aßmus } 324*968ec77eSStephan Aßmus 325*968ec77eSStephan Aßmus 326*968ec77eSStephan Aßmus bool 327*968ec77eSStephan Aßmus PersonView::IsTextSelected() const 328*968ec77eSStephan Aßmus { 329*968ec77eSStephan Aßmus for (int32 i = fControls.CountItems() - 1; i >= 0; i--) { 330*968ec77eSStephan Aßmus BTextView* text = fControls.ItemAt(i)->TextView(); 331*968ec77eSStephan Aßmus 332*968ec77eSStephan Aßmus int32 start, end; 333*968ec77eSStephan Aßmus text->GetSelection(&start, &end); 334*968ec77eSStephan Aßmus if (start != end) 335*968ec77eSStephan Aßmus return true; 336*968ec77eSStephan Aßmus } 337*968ec77eSStephan Aßmus return false; 338*968ec77eSStephan Aßmus } 339