RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / apps / mail / AddressTextControl.cpp
bloba8a81afbe350463c5c5859585d942438a073e3a1
1 /*
2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
4 * Distributed under the terms of the MIT License.
5 */
8 #include "AddressTextControl.h"
10 #include <Autolock.h>
11 #include <Button.h>
12 #include <Catalog.h>
13 #include <ControlLook.h>
14 #include <Clipboard.h>
15 #include <File.h>
16 #include <LayoutBuilder.h>
17 #include <Locale.h>
18 #include <LayoutUtils.h>
19 #include <NodeInfo.h>
20 #include <PopUpMenu.h>
21 #include <SeparatorView.h>
22 #include <TextView.h>
23 #include <Window.h>
25 #include <stdio.h>
26 #include <stdlib.h>
28 #include "MailApp.h"
29 #include "Messages.h"
30 #include "QueryList.h"
31 #include "TextViewCompleter.h"
34 #undef B_TRANSLATION_CONTEXT
35 #define B_TRANSLATION_CONTEXT "AddressTextControl"
38 static const uint32 kMsgAddAddress = 'adad';
39 static const float kVerticalTextRectInset = 2.0;
42 class AddressTextControl::TextView : public BTextView {
43 private:
44 static const uint32 MSG_CLEAR = 'cler';
46 public:
47 TextView(AddressTextControl* parent);
48 virtual ~TextView();
50 virtual void MessageReceived(BMessage* message);
51 virtual void FrameResized(float width, float height);
52 virtual void KeyDown(const char* bytes, int32 numBytes);
53 virtual void MakeFocus(bool focused = true);
55 virtual BSize MinSize();
56 virtual BSize MaxSize();
58 const BMessage* ModificationMessage() const;
59 void SetModificationMessage(BMessage* message);
61 void SetUpdateAutoCompleterChoices(bool update);
63 protected:
64 virtual void InsertText(const char* text, int32 length,
65 int32 offset,
66 const text_run_array* runs);
67 virtual void DeleteText(int32 fromOffset, int32 toOffset);
69 private:
70 void _AlignTextRect();
72 private:
73 AddressTextControl* fAddressTextControl;
74 TextViewCompleter* fAutoCompleter;
75 BString fPreviousText;
76 bool fUpdateAutoCompleterChoices;
77 BMessage* fModificationMessage;
81 class AddressPopUpMenu : public BPopUpMenu, public QueryListener {
82 public:
83 AddressPopUpMenu();
84 virtual ~AddressPopUpMenu();
86 protected:
87 virtual void EntryCreated(QueryList& source,
88 const entry_ref& ref, ino_t node);
89 virtual void EntryRemoved(QueryList& source,
90 const node_ref& nodeRef);
92 private:
93 void _RebuildMenu();
94 void _AddGroup(const char* label, const char* group,
95 PersonList& peopleList);
96 void _AddPeople(BMenu* menu, PersonList& peopleList,
97 const char* group,
98 bool addSeparator = false);
99 bool _MatchesGroup(const Person& person,
100 const char* group);
104 class AddressTextControl::PopUpButton : public BControl {
105 public:
106 PopUpButton();
107 virtual ~PopUpButton();
109 virtual BSize MinSize();
110 virtual BSize PreferredSize();
111 virtual BSize MaxSize();
113 virtual void MouseDown(BPoint where);
114 virtual void Draw(BRect updateRect);
116 private:
117 AddressPopUpMenu* fPopUpMenu;
121 class PeopleChoiceModel : public BAutoCompleter::ChoiceModel {
122 public:
123 PeopleChoiceModel()
125 fChoices(5, true)
129 ~PeopleChoiceModel()
133 virtual void FetchChoicesFor(const BString& pattern)
135 // Remove all existing choices
136 fChoices.MakeEmpty();
138 // Search through the people list for any matches
139 PersonList& peopleList = static_cast<TMailApp*>(be_app)->People();
140 BAutolock locker(peopleList);
142 for (int32 index = 0; index < peopleList.CountPersons(); index++) {
143 const Person* person = peopleList.PersonAt(index);
145 const BString& baseText = person->Name();
146 for (int32 addressIndex = 0;
147 addressIndex < person->CountAddresses(); addressIndex++) {
148 BString choiceText = baseText;
149 choiceText << " <" << person->AddressAt(addressIndex) << ">";
151 int32 match = choiceText.IFindFirst(pattern);
152 if (match < 0)
153 continue;
155 fChoices.AddItem(new BAutoCompleter::Choice(choiceText,
156 choiceText, match, pattern.Length()));
160 locker.Unlock();
161 fChoices.SortItems(_CompareChoices);
164 virtual int32 CountChoices() const
166 return fChoices.CountItems();
169 virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
171 return fChoices.ItemAt(index);
174 static int _CompareChoices(const BAutoCompleter::Choice* a,
175 const BAutoCompleter::Choice* b)
177 return a->DisplayText().Compare(b->DisplayText());
180 private:
181 BObjectList<BAutoCompleter::Choice> fChoices;
185 // #pragma mark - TextView
188 AddressTextControl::TextView::TextView(AddressTextControl* parent)
190 BTextView("mail"),
191 fAddressTextControl(parent),
192 fAutoCompleter(new TextViewCompleter(this,
193 new PeopleChoiceModel())),
194 fPreviousText(""),
195 fUpdateAutoCompleterChoices(true)
197 MakeResizable(true);
198 SetStylable(true);
199 fAutoCompleter->SetModificationsReported(true);
203 AddressTextControl::TextView::~TextView()
205 delete fAutoCompleter;
209 void
210 AddressTextControl::TextView::MessageReceived(BMessage* message)
212 switch (message->what) {
213 case MSG_CLEAR:
214 SetText("");
215 break;
217 default:
218 BTextView::MessageReceived(message);
219 break;
224 void
225 AddressTextControl::TextView::FrameResized(float width, float height)
227 BTextView::FrameResized(width, height);
228 _AlignTextRect();
232 void
233 AddressTextControl::TextView::KeyDown(const char* bytes, int32 numBytes)
235 switch (bytes[0]) {
236 case B_TAB:
237 BView::KeyDown(bytes, numBytes);
238 break;
240 case B_ESCAPE:
241 // Revert to text as it was when we received keyboard focus.
242 SetText(fPreviousText.String());
243 SelectAll();
244 break;
246 case B_RETURN:
247 // Don't let this through to the text view.
248 break;
250 default:
251 BTextView::KeyDown(bytes, numBytes);
252 break;
256 void
257 AddressTextControl::TextView::MakeFocus(bool focus)
259 if (focus == IsFocus())
260 return;
262 BTextView::MakeFocus(focus);
264 if (focus) {
265 fPreviousText = Text();
266 SelectAll();
269 fAddressTextControl->Invalidate();
273 BSize
274 AddressTextControl::TextView::MinSize()
276 BSize min;
277 min.height = ceilf(LineHeight(0) + kVerticalTextRectInset);
278 // we always add at least one pixel vertical inset top/bottom for
279 // the text rect.
280 min.width = min.height * 3;
281 return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
285 BSize
286 AddressTextControl::TextView::MaxSize()
288 BSize max(MinSize());
289 max.width = B_SIZE_UNLIMITED;
290 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
294 const BMessage*
295 AddressTextControl::TextView::ModificationMessage() const
297 return fModificationMessage;
301 void
302 AddressTextControl::TextView::SetModificationMessage(BMessage* message)
304 fModificationMessage = message;
308 void
309 AddressTextControl::TextView::SetUpdateAutoCompleterChoices(bool update)
311 fUpdateAutoCompleterChoices = update;
315 void
316 AddressTextControl::TextView::InsertText(const char* text,
317 int32 length, int32 offset, const text_run_array* runs)
319 if (!strncmp(text, "mailto:", 7)) {
320 text += 7;
321 length -= 7;
322 if (runs != NULL)
323 runs = NULL;
326 // Filter all line breaks, note that text is not terminated.
327 if (length == 1) {
328 if (*text == '\n' || *text == '\r')
329 BTextView::InsertText(" ", 1, offset, runs);
330 else
331 BTextView::InsertText(text, 1, offset, runs);
332 } else {
333 BString filteredText(text, length);
334 filteredText.ReplaceAll('\n', ' ');
335 filteredText.ReplaceAll('\r', ' ');
336 BTextView::InsertText(filteredText.String(), length, offset,
337 runs);
340 // TODO: change E-mail representation
342 // Make the base URL part bold.
343 BString text(Text(), TextLength());
344 int32 baseUrlStart = text.FindFirst("://");
345 if (baseUrlStart >= 0)
346 baseUrlStart += 3;
347 else
348 baseUrlStart = 0;
349 int32 baseUrlEnd = text.FindFirst("/", baseUrlStart);
350 if (baseUrlEnd < 0)
351 baseUrlEnd = TextLength();
353 BFont font;
354 GetFont(&font);
355 const rgb_color black = (rgb_color) { 0, 0, 0, 255 };
356 const rgb_color gray = (rgb_color) { 60, 60, 60, 255 };
357 if (baseUrlStart > 0)
358 SetFontAndColor(0, baseUrlStart, &font, B_FONT_ALL, &gray);
359 if (baseUrlEnd > baseUrlStart) {
360 font.SetFace(B_BOLD_FACE);
361 SetFontAndColor(baseUrlStart, baseUrlEnd, &font, B_FONT_ALL, &black);
363 if (baseUrlEnd < TextLength()) {
364 font.SetFace(B_REGULAR_FACE);
365 SetFontAndColor(baseUrlEnd, TextLength(), &font, B_FONT_ALL, &gray);
368 fAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
369 fAddressTextControl->InvokeNotify(fModificationMessage,
370 B_CONTROL_MODIFIED);
374 void
375 AddressTextControl::TextView::DeleteText(int32 fromOffset,
376 int32 toOffset)
378 BTextView::DeleteText(fromOffset, toOffset);
380 fAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
381 fAddressTextControl->InvokeNotify(fModificationMessage,
382 B_CONTROL_MODIFIED);
386 void
387 AddressTextControl::TextView::_AlignTextRect()
389 // Layout the text rect to be in the middle, normally this means there
390 // is one pixel spacing on each side.
391 BRect textRect(Bounds());
392 textRect.left = 0.0;
393 float vInset = max_c(1,
394 floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
396 float hInset = 0;
397 if (be_control_look != NULL)
398 hInset = be_control_look->DefaultLabelSpacing();
400 textRect.InsetBy(hInset, vInset);
401 SetTextRect(textRect);
405 // #pragma mark - PopUpButton
408 AddressTextControl::PopUpButton::PopUpButton()
410 BControl(NULL, NULL, NULL, B_WILL_DRAW)
412 fPopUpMenu = new AddressPopUpMenu();
416 AddressTextControl::PopUpButton::~PopUpButton()
418 delete fPopUpMenu;
422 BSize
423 AddressTextControl::PopUpButton::MinSize()
425 // TODO: BControlLook does not give us any size information!
426 return BSize(10, 10);
430 BSize
431 AddressTextControl::PopUpButton::PreferredSize()
433 return BSize(10, B_SIZE_UNSET);
437 BSize
438 AddressTextControl::PopUpButton::MaxSize()
440 return BSize(10, B_SIZE_UNLIMITED);
444 void
445 AddressTextControl::PopUpButton::MouseDown(BPoint where)
447 if (fPopUpMenu->Parent() != NULL)
448 return;
450 float width;
451 fPopUpMenu->GetPreferredSize(&width, NULL);
452 fPopUpMenu->SetTargetForItems(Parent());
454 BPoint point(Bounds().Width() - width, Bounds().Height() + 2);
455 ConvertToScreen(&point);
456 fPopUpMenu->Go(point, true, true, true);
460 void
461 AddressTextControl::PopUpButton::Draw(BRect updateRect)
463 uint32 flags = 0;
464 if (!IsEnabled())
465 flags |= BControlLook::B_DISABLED;
467 if (IsFocus() && Window()->IsActive())
468 flags |= BControlLook::B_FOCUSED;
470 rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
471 BRect rect = Bounds();
472 be_control_look->DrawMenuFieldBackground(this, rect,
473 updateRect, base, true, flags);
477 // #pragma mark - PopUpMenu
480 AddressPopUpMenu::AddressPopUpMenu()
482 BPopUpMenu("", true)
484 static_cast<TMailApp*>(be_app)->PeopleQueryList().AddListener(this);
488 AddressPopUpMenu::~AddressPopUpMenu()
490 static_cast<TMailApp*>(be_app)->PeopleQueryList().RemoveListener(this);
494 void
495 AddressPopUpMenu::EntryCreated(QueryList& source,
496 const entry_ref& ref, ino_t node)
498 _RebuildMenu();
502 void
503 AddressPopUpMenu::EntryRemoved(QueryList& source,
504 const node_ref& nodeRef)
506 _RebuildMenu();
510 void
511 AddressPopUpMenu::_RebuildMenu()
513 // Remove all items
514 int32 index = CountItems();
515 while (index-- > 0) {
516 delete RemoveItem(index);
519 // Rebuild contents
520 PersonList& peopleList = static_cast<TMailApp*>(be_app)->People();
521 BAutolock locker(peopleList);
523 if (peopleList.CountPersons() > 0)
524 _AddGroup(B_TRANSLATE("All people"), NULL, peopleList);
526 GroupList& groupList = static_cast<TMailApp*>(be_app)->PeopleGroups();
527 BAutolock groupLocker(groupList);
529 for (int32 index = 0; index < groupList.CountGroups(); index++) {
530 BString group = groupList.GroupAt(index);
531 _AddGroup(group, group, peopleList);
534 groupLocker.Unlock();
536 _AddPeople(this, peopleList, "", true);
540 void
541 AddressPopUpMenu::_AddGroup(const char* label, const char* group,
542 PersonList& peopleList)
544 BMenu* menu = new BMenu(label);
545 AddItem(menu);
546 menu->Superitem()->SetMessage(new BMessage(kMsgAddAddress));
548 _AddPeople(menu, peopleList, group);
552 void
553 AddressPopUpMenu::_AddPeople(BMenu* menu, PersonList& peopleList,
554 const char* group, bool addSeparator)
556 for (int32 index = 0; index < peopleList.CountPersons(); index++) {
557 const Person* person = peopleList.PersonAt(index);
558 if (!_MatchesGroup(*person, group))
559 continue;
561 if (person->CountAddresses() != 0 && addSeparator) {
562 menu->AddSeparatorItem();
563 addSeparator = false;
566 for (int32 addressIndex = 0; addressIndex < person->CountAddresses();
567 addressIndex++) {
568 BString email = person->Name();
569 email << " <" << person->AddressAt(addressIndex) << ">";
571 BMessage* message = new BMessage(kMsgAddAddress);
572 message->AddString("email", email);
573 menu->AddItem(new BMenuItem(email, message));
575 if (menu->Superitem() != NULL)
576 menu->Superitem()->Message()->AddString("email", email);
582 bool
583 AddressPopUpMenu::_MatchesGroup(const Person& person, const char* group)
585 if (group == NULL)
586 return true;
588 if (group[0] == '\0')
589 return person.CountGroups() == 0;
591 return person.IsInGroup(group);
595 // TODO: sort lists!
597 void
598 AddressTextControl::PopUpMenu::_AddPersonItem(const entry_ref *ref, ino_t node, BString &name,
599 BString &email, const char *attr, BMenu *groupMenu, BMenuItem *superItem)
601 BString label;
602 BString sortKey;
603 // For alphabetical order sorting, usually last name.
605 // if we have no Name, just use the email address
606 if (name.Length() == 0) {
607 label = email;
608 sortKey = email;
609 } else {
610 // otherwise, pretty-format it
611 label << name << " (" << email << ")";
613 // Extract the last name (last word in the name),
614 // removing trailing and leading spaces.
615 const char *nameStart = name.String();
616 const char *string = nameStart + strlen(nameStart) - 1;
617 const char *wordEnd;
619 while (string >= nameStart && isspace(*string))
620 string--;
621 wordEnd = string + 1; // Points to just after last word.
622 while (string >= nameStart && !isspace(*string))
623 string--;
624 string++; // Point to first letter in the word.
625 if (wordEnd > string)
626 sortKey.SetTo(string, wordEnd - string);
627 else // Blank name, pretend that the last name is after it.
628 string = nameStart + strlen(nameStart);
630 // Append the first names to the end, so that people with the same last
631 // name get sorted by first name. Note no space between the end of the
632 // last name and the start of the first names, but that shouldn't
633 // matter for sorting.
634 sortKey.Append(nameStart, string - nameStart);
639 // #pragma mark - AddressTextControl
642 AddressTextControl::AddressTextControl(const char* name, BMessage* message)
644 BControl(name, NULL, message, B_WILL_DRAW),
645 fRefDropMenu(NULL),
646 fWindowActive(false),
647 fEditable(true)
649 fTextView = new TextView(this);
650 fTextView->SetExplicitMinSize(BSize(100, B_SIZE_UNSET));
651 fPopUpButton = new PopUpButton();
653 BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
654 .SetInsets(2)
655 .Add(fTextView)
656 .Add(fPopUpButton);
658 SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
659 SetLowUIColor(ViewUIColor());
660 SetViewUIColor(fTextView->ViewUIColor());
662 SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
663 B_ALIGN_VERTICAL_CENTER));
665 SetEnabled(fEditable);
666 // Sets the B_NAVIGABLE flag on the TextView
670 AddressTextControl::~AddressTextControl()
675 void
676 AddressTextControl::AttachedToWindow()
678 BControl::AttachedToWindow();
679 fWindowActive = Window()->IsActive();
683 void
684 AddressTextControl::WindowActivated(bool active)
686 BControl::WindowActivated(active);
687 if (fWindowActive != active) {
688 fWindowActive = active;
689 Invalidate();
694 void
695 AddressTextControl::Draw(BRect updateRect)
697 if (!IsEditable())
698 return;
700 BRect bounds(Bounds());
701 rgb_color base(LowColor());
702 uint32 flags = 0;
703 if (!IsEnabled())
704 flags |= BControlLook::B_DISABLED;
705 if (fWindowActive && fTextView->IsFocus())
706 flags |= BControlLook::B_FOCUSED;
707 be_control_look->DrawTextControlBorder(this, bounds, updateRect, base,
708 flags);
712 void
713 AddressTextControl::MakeFocus(bool focus)
715 // Forward this to the text view, we never accept focus ourselves.
716 fTextView->MakeFocus(focus);
720 void
721 AddressTextControl::SetEnabled(bool enabled)
723 BControl::SetEnabled(enabled);
724 fTextView->MakeEditable(enabled && fEditable);
725 if (enabled)
726 fTextView->SetFlags(fTextView->Flags() | B_NAVIGABLE);
727 else
728 fTextView->SetFlags(fTextView->Flags() & ~B_NAVIGABLE);
730 fPopUpButton->SetEnabled(enabled);
732 _UpdateTextViewColors();
736 void
737 AddressTextControl::MessageReceived(BMessage* message)
739 switch (message->what) {
740 case B_SIMPLE_DATA:
742 int32 buttons = -1;
743 BPoint point;
744 if (message->FindInt32("buttons", &buttons) != B_OK)
745 buttons = B_PRIMARY_MOUSE_BUTTON;
747 if (buttons != B_PRIMARY_MOUSE_BUTTON
748 && message->FindPoint("_drop_point_", &point) != B_OK)
749 return;
751 BMessage forwardRefs(B_REFS_RECEIVED);
752 bool forward = false;
754 entry_ref ref;
755 for (int32 index = 0;message->FindRef("refs", index, &ref) == B_OK; index++) {
756 BFile file(&ref, B_READ_ONLY);
757 if (file.InitCheck() == B_NO_ERROR) {
758 BNodeInfo info(&file);
759 char type[B_FILE_NAME_LENGTH];
760 info.GetType(type);
762 if (!strcmp(type,"application/x-person")) {
763 // add person's E-mail address to the To: field
765 BString attr = "";
766 if (buttons == B_PRIMARY_MOUSE_BUTTON) {
767 if (message->FindString("attr", &attr) < B_OK)
768 attr = "META:email";
769 } else {
770 BNode node(&ref);
771 node.RewindAttrs();
773 char buffer[B_ATTR_NAME_LENGTH];
775 delete fRefDropMenu;
776 fRefDropMenu = new BPopUpMenu("RecipientMenu");
778 while (node.GetNextAttrName(buffer) == B_OK) {
779 if (strstr(buffer, "email") == NULL)
780 continue;
782 attr = buffer;
784 BString address;
785 node.ReadAttrString(buffer, &address);
786 if (address.Length() <= 0)
787 continue;
789 BMessage* itemMsg
790 = new BMessage(kMsgAddAddress);
791 itemMsg->AddString("email", address.String());
793 BMenuItem* item = new BMenuItem(
794 address.String(), itemMsg);
795 fRefDropMenu->AddItem(item);
798 if (fRefDropMenu->CountItems() > 1) {
799 fRefDropMenu->SetTargetForItems(this);
800 fRefDropMenu->Go(point, true, true, true);
801 return;
802 } else {
803 delete fRefDropMenu;
804 fRefDropMenu = NULL;
808 BString email;
809 file.ReadAttrString(attr.String(), &email);
811 // we got something...
812 if (email.Length() > 0) {
813 // see if we can get a username as well
814 BString name;
815 file.ReadAttrString("META:name", &name);
817 BString address;
818 if (name.Length() == 0) {
819 // if we have no Name, just use the email address
820 address = email;
821 } else {
822 // otherwise, pretty-format it
823 address << "\"" << name << "\" <" << email << ">";
826 _AddAddress(address);
828 } else {
829 forward = true;
830 forwardRefs.AddRef("refs", &ref);
835 if (forward) {
836 // Pass on to parent
837 Window()->PostMessage(&forwardRefs, Parent());
839 break;
842 case M_SELECT:
844 BTextView *textView = (BTextView *)ChildAt(0);
845 if (textView != NULL)
846 textView->Select(0, textView->TextLength());
847 break;
850 case kMsgAddAddress:
852 const char* email;
853 for (int32 index = 0;
854 message->FindString("email", index++, &email) == B_OK;)
855 _AddAddress(email);
856 break;
859 default:
860 BControl::MessageReceived(message);
861 break;
866 const BMessage*
867 AddressTextControl::ModificationMessage() const
869 return fTextView->ModificationMessage();
873 void
874 AddressTextControl::SetModificationMessage(BMessage* message)
876 fTextView->SetModificationMessage(message);
880 bool
881 AddressTextControl::IsEditable() const
883 return fEditable;
887 void
888 AddressTextControl::SetEditable(bool editable)
890 fTextView->MakeEditable(IsEnabled() && editable);
891 fEditable = editable;
893 if (editable && fPopUpButton->IsHidden(this))
894 fPopUpButton->Show();
895 else if (!editable && !fPopUpButton->IsHidden(this))
896 fPopUpButton->Hide();
900 void
901 AddressTextControl::SetText(const char* text)
903 if (text == NULL || Text() == NULL || strcmp(Text(), text) != 0) {
904 fTextView->SetUpdateAutoCompleterChoices(false);
905 fTextView->SetText(text);
906 fTextView->SetUpdateAutoCompleterChoices(true);
911 const char*
912 AddressTextControl::Text() const
914 return fTextView->Text();
918 int32
919 AddressTextControl::TextLength() const
921 return fTextView->TextLength();
925 void
926 AddressTextControl::GetSelection(int32* start, int32* end) const
928 fTextView->GetSelection(start, end);
932 void
933 AddressTextControl::Select(int32 start, int32 end)
935 fTextView->Select(start, end);
939 void
940 AddressTextControl::SelectAll()
942 fTextView->Select(0, TextLength());
946 bool
947 AddressTextControl::HasFocus()
949 return fTextView->IsFocus();
953 void
954 AddressTextControl::_AddAddress(const char* text)
956 int last = fTextView->TextLength();
957 if (last != 0) {
958 fTextView->Select(last, last);
959 // TODO: test if there is already a ','
960 fTextView->Insert(", ");
962 fTextView->Insert(text);
966 void
967 AddressTextControl::_UpdateTextViewColors()
969 BFont font;
970 fTextView->GetFontAndColor(0, &font);
972 rgb_color textColor;
973 if (!IsEditable() || IsEnabled())
974 textColor = ui_color(B_DOCUMENT_TEXT_COLOR);
975 else {
976 textColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
977 B_DISABLED_LABEL_TINT);
980 fTextView->SetFontAndColor(&font, B_FONT_ALL, &textColor);
982 rgb_color color;
983 if (!IsEditable())
984 color = ui_color(B_PANEL_BACKGROUND_COLOR);
985 else if (IsEnabled())
986 color = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
987 else {
988 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
989 B_LIGHTEN_2_TINT);
992 fTextView->SetViewColor(color);
993 fTextView->SetLowColor(color);