vfs: check userland buffers before reading them.
[haiku.git] / src / apps / webpositive / BookmarkBar.cpp
blob05f1902c1011a49da37caa1fe08e0093c49d8295
1 /*
2 * Copyright 2014, Adrien Destugues <pulkomandy@pulkomandy.tk>.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "BookmarkBar.h"
9 #include <Directory.h>
10 #include <Entry.h>
11 #include <IconMenuItem.h>
12 #include <Messenger.h>
13 #include <Window.h>
15 #include "NavMenu.h"
17 #include <stdio.h>
20 BookmarkBar::BookmarkBar(const char* title, BHandler* target,
21 const entry_ref* navDir)
23 BMenuBar(title)
25 SetFlags(Flags() | B_FRAME_EVENTS);
26 BEntry(navDir).GetNodeRef(&fNodeRef);
28 fOverflowMenu = new BMenu(B_UTF8_ELLIPSIS);
29 AddItem(fOverflowMenu);
33 BookmarkBar::~BookmarkBar()
35 stop_watching(BMessenger(this));
39 void
40 BookmarkBar::AttachedToWindow()
42 BMenuBar::AttachedToWindow();
43 watch_node(&fNodeRef, B_WATCH_DIRECTORY, BMessenger(this));
45 // Enumerate initial directory content
46 BDirectory dir(&fNodeRef);
47 BEntry bookmark;
48 while (dir.GetNextEntry(&bookmark, true) == B_OK) {
49 node_ref ref;
50 if (bookmark.GetNodeRef(&ref) == B_OK)
51 _AddItem(ref.node, &bookmark);
56 void
57 BookmarkBar::MessageReceived(BMessage* message)
59 switch (message->what) {
60 case B_NODE_MONITOR:
62 int32 opcode = message->FindInt32("opcode");
63 ino_t inode = message->FindInt64("node");
64 switch (opcode) {
65 case B_ENTRY_CREATED:
67 entry_ref ref;
68 const char* name;
70 message->FindInt32("device", &ref.device);
71 message->FindInt64("directory", &ref.directory);
72 message->FindString("name", &name);
73 ref.set_name(name);
75 BEntry entry(&ref, true);
76 if (entry.InitCheck() == B_OK)
77 _AddItem(inode, &entry);
78 break;
80 case B_ENTRY_MOVED:
82 entry_ref ref;
83 const char *name;
85 message->FindInt32("device", &ref.device);
86 message->FindInt64("to directory", &ref.directory);
87 message->FindString("name", &name);
88 ref.set_name(name);
90 if (fItemsMap[inode] == NULL) {
91 BEntry entry(&ref, true);
92 _AddItem(inode, &entry);
93 break;
94 } else {
95 // Existing item. Check if it's a rename or a move
96 // to some other folder.
97 ino_t from, to;
98 message->FindInt64("to directory", &to);
99 message->FindInt64("from directory", &from);
100 if (from == to) {
101 const char *name;
102 if (message->FindString("name", &name) == B_OK)
103 fItemsMap[inode]->SetLabel(name);
105 BMessage* itemMessage = new BMessage(
106 B_REFS_RECEIVED);
107 itemMessage->AddRef("refs", &ref);
108 fItemsMap[inode]->SetMessage(itemMessage);
110 break;
114 // fall through: the item was moved from here to
115 // elsewhere, remove it from the bar.
117 case B_ENTRY_REMOVED:
119 IconMenuItem* item = fItemsMap[inode];
120 RemoveItem(item);
121 fOverflowMenu->RemoveItem(item);
122 fItemsMap.erase(inode);
123 delete item;
126 return;
130 BMenuBar::MessageReceived(message);
134 void
135 BookmarkBar::FrameResized(float width, float height)
137 int32 count = CountItems() - 1;
138 // We don't touch the "more" menu
139 int32 i = 0;
140 float rightmost = 0.f;
141 while (i < count) {
142 BMenuItem* item = ItemAt(i);
143 BRect frame = item->Frame();
144 if (frame.right > width - 32)
145 break;
146 rightmost = frame.right;
147 i++;
150 if (i == count) {
151 // See if we can move some items from the "more" menu in the remaining
152 // space.
153 BMenuItem* extraItem = fOverflowMenu->ItemAt(0);
154 while (extraItem != NULL) {
155 BRect frame = extraItem->Frame();
156 if (frame.Width() + rightmost > width - 32)
157 break;
159 AddItem(fOverflowMenu->RemoveItem((int32)0), i);
160 i++;
162 extraItem = fOverflowMenu->ItemAt(0);
164 } else {
165 // Remove any overflowing item and move them to the "more" menu.
166 for (int j = i; j < count; j++)
167 fOverflowMenu->AddItem(RemoveItem(j));
172 BSize
173 BookmarkBar::MinSize()
175 BSize size = BMenuBar::MinSize();
177 // We only need space to show the "more" button.
178 size.width = 32;
180 // We need enough vertical space to show bookmark icons.
181 if (size.height < 20)
182 size.height = 20;
184 return size;
188 // #pragma mark - private methods
191 void
192 BookmarkBar::_AddItem(ino_t inode, BEntry* entry)
194 char name[B_FILE_NAME_LENGTH];
195 entry->GetName(name);
197 // make sure the item doesn't already exists
198 if (fItemsMap[inode] != NULL)
199 return;
201 entry_ref ref;
202 entry->GetRef(&ref);
204 IconMenuItem* item = NULL;
206 if (entry->IsDirectory()) {
207 BNavMenu* menu = new BNavMenu(name, B_REFS_RECEIVED, Window());
208 menu->SetNavDir(&ref);
209 item = new IconMenuItem(menu, NULL,
210 "application/x-vnd.Be-directory", B_MINI_ICON);
212 } else {
213 BNode node(entry);
214 BNodeInfo info(&node);
216 BMessage* message = new BMessage(B_REFS_RECEIVED);
217 message->AddRef("refs", &ref);
218 item = new IconMenuItem(name, message, &info, B_MINI_ICON);
221 int32 count = CountItems();
223 BMenuBar::AddItem(item, count - 1);
224 fItemsMap[inode] = item;
226 // Move the item to the "more" menu if it overflows.
227 BRect r = Bounds();
228 FrameResized(r.Width(), r.Height());