hrev53404 adds 2 changesets to branch 'master'
old head: 79d1a09c19f5c1326377ec5f4d9e23a29cb89790
new head: 2140520f96938f8af89a3f13eb8d5aea793532fc
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=2140520f9693+%5E79d1a09c19f5
----------------------------------------------------------------------------
ebb30434c9ce: Tracker: move AttributeView to own file and rename
Change-Id: I046eb9aa0fef792e9e940d0a6dfd887ede2fa996
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1744
Reviewed-by: waddlesplash <waddlesplash@xxxxxxxxx>
2140520f9693: Tracker InfoWindow: layoutify, use tabs
- Use layout kit to make a few things simpler
- Separate the view showing the header (icon/name) and the one showing
the extra details, making two simpler files instead of a complex one
- Fix some layouting issues
- The permissions are now in a second tab, allowing to add a third one
with other things (more on that later)
screenshot: http://pulkomandy.tk/drop/fileinfo.png
Change-Id: Ief80815eba749723664f40f1317f8aa4cf692162
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1745
Reviewed-by: Ryan Leavengood <leavengood@xxxxxxxxx>
[ Adrien Destugues <pulkomandy@xxxxxxxxxxxxx> ]
----------------------------------------------------------------------------
8 files changed, 2098 insertions(+), 1728 deletions(-)
src/kits/tracker/Jamfile | 2 +
.../tracker/infowindow/FilePermissionsView.cpp | 2 +-
src/kits/tracker/infowindow/GeneralInfoView.cpp | 1089 +++++++++++
src/kits/tracker/infowindow/GeneralInfoView.h | 129 ++
src/kits/tracker/infowindow/HeaderView.cpp | 724 +++++++
src/kits/tracker/infowindow/HeaderView.h | 110 ++
src/kits/tracker/infowindow/InfoWindow.cpp | 1764 +-----------------
src/kits/tracker/infowindow/InfoWindow.h | 6 +-
############################################################################
Commit: ebb30434c9ced39350f9dd0e5af045da6d5df5e2
URL: https://git.haiku-os.org/haiku/commit/?id=ebb30434c9ce
Author: Adrien Destugues <pulkomandy@xxxxxxxxxxxxx>
Date: Sun Aug 25 08:40:53 2019 UTC
Committer: waddlesplash <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Aug 25 19:17:14 2019 UTC
Tracker: move AttributeView to own file and rename
Change-Id: I046eb9aa0fef792e9e940d0a6dfd887ede2fa996
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1744
Reviewed-by: waddlesplash <waddlesplash@xxxxxxxxx>
----------------------------------------------------------------------------
diff --git a/src/kits/tracker/Jamfile b/src/kits/tracker/Jamfile
index 31a2ba1c5d..edb5b2767c 100644
--- a/src/kits/tracker/Jamfile
+++ b/src/kits/tracker/Jamfile
@@ -44,6 +44,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
FilePanelPriv.cpp
FilePermissionsView.cpp
FindPanel.cpp
+ GeneralInfoView.cpp
GroupedMenu.cpp
IconCache.cpp
IconMenuItem.cpp
diff --git a/src/kits/tracker/infowindow/GeneralInfoView.cpp
b/src/kits/tracker/infowindow/GeneralInfoView.cpp
new file mode 100644
index 0000000000..f77ec73146
--- /dev/null
+++ b/src/kits/tracker/infowindow/GeneralInfoView.cpp
@@ -0,0 +1,1646 @@
+/*
+Open Tracker License
+
+Terms and Conditions
+
+Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice applies to all licensees
+and shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN
CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Be Incorporated shall not be
+used in advertising or otherwise to promote the sale, use or other dealings in
+this Software without prior written authorization from Be Incorporated.
+
+Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
trademarks
+of Be Incorporated in the United States and other countries. Other brand
product
+names are registered trademarks or trademarks of their respective holders.
+All rights reserved.
+*/
+
+
+#include "GeneralInfoView.h"
+
+#include <Alert.h>
+#include <Application.h>
+#include <Catalog.h>
+#include <Locale.h>
+#include <NodeMonitor.h>
+#include <PopUpMenu.h>
+#include <Region.h>
+#include <Roster.h>
+#include <Screen.h>
+#include <ScrollView.h>
+#include <StringFormat.h>
+#include <SymLink.h>
+#include <Volume.h>
+#include <VolumeRoster.h>
+#include <Window.h>
+
+#include "Attributes.h"
+#include "Commands.h"
+#include "FSUtils.h"
+#include "IconMenuItem.h"
+#include "InfoWindow.h"
+#include "Model.h"
+#include "NavMenu.h"
+#include "PoseView.h"
+#include "StringForSize.h"
+#include "Tracker.h"
+#include "WidgetAttributeText.h"
+
+
+#undef B_TRANSLATION_CONTEXT
+#define B_TRANSLATION_CONTEXT "InfoWindow"
+
+
+namespace BPrivate {
+
+class TrackingView : public BControl {
+public:
+ TrackingView(BRect, const char* str, BMessage* message);
+
+ virtual void MouseDown(BPoint);
+ virtual void MouseMoved(BPoint where, uint32 transit, const BMessage*);
+ virtual void MouseUp(BPoint);
+ virtual void Draw(BRect);
+
+private:
+ bool fMouseDown;
+ bool fMouseInView;
+};
+
+} // namespace BPrivate
+
+
+// Offsets taken from TAlertView::Draw in BAlert.cpp
+const float kIconHorizOffset = 18.0f;
+const float kIconVertOffset = 6.0f;
+
+const float kBorderMargin = 15.0f;
+const float kDrawMargin = 3.0f;
+
+// Amount you have to move the mouse before a drag starts
+const float kDragSlop = 3.0f;
+
+
+const uint32 kSetPreferredApp = 'setp';
+const uint32 kSelectNewSymTarget = 'snew';
+const uint32 kOpenLinkSource = 'opls';
+const uint32 kOpenLinkTarget = 'oplt';
+
+
+static void
+OpenParentAndSelectOriginal(const entry_ref* ref)
+{
+ BEntry entry(ref);
+ node_ref node;
+ entry.GetNodeRef(&node);
+
+ BEntry parent;
+ entry.GetParent(&parent);
+ entry_ref parentRef;
+ parent.GetRef(&parentRef);
+
+ BMessage message(B_REFS_RECEIVED);
+ message.AddRef("refs", &parentRef);
+ message.AddData("nodeRefToSelect", B_RAW_TYPE, &node, sizeof(node_ref));
+
+ be_app->PostMessage(&message);
+}
+
+
+static BWindow*
+OpenToolTipWindow(BScreen& screen, BRect rect, const char* name,
+ const char* string, BMessenger target, BMessage* message)
+{
+ font_height fontHeight;
+ be_plain_font->GetHeight(&fontHeight);
+ float height = ceilf(fontHeight.ascent + fontHeight.descent);
+ rect.top = floorf(rect.top + (rect.Height() - height) / 2.0f);
+ rect.bottom = rect.top + height;
+
+ rect.right = rect.left + ceilf(be_plain_font->StringWidth(string)) + 4;
+ if (rect.left < 0)
+ rect.OffsetBy(-rect.left, 0);
+ else if (rect.right > screen.Frame().right)
+ rect.OffsetBy(screen.Frame().right - rect.right, 0);
+
+ BWindow* window = new BWindow(rect, name, B_BORDERED_WINDOW_LOOK,
+ B_FLOATING_ALL_WINDOW_FEEL,
+ B_NOT_MOVABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE |
B_NOT_MINIMIZABLE
+ | B_NOT_RESIZABLE | B_AVOID_FOCUS | B_NO_WORKSPACE_ACTIVATION
+ | B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS);
+
+ TrackingView* trackingView = new TrackingView(window->Bounds(),
+ string, message);
+ trackingView->SetTarget(target);
+ window->AddChild(trackingView);
+
+ window->Sync();
+ window->Show();
+
+ return window;
+}
+
+
+GeneralInfoView::GeneralInfoView(BRect rect, Model* model)
+ :
+ BView(rect, "attr_view", B_FOLLOW_ALL_SIDES,
+ B_WILL_DRAW | B_PULSE_NEEDED),
+ fDivider(0),
+ fPreferredAppMenu(NULL),
+ fModel(model),
+ fIconModel(model),
+ fMouseDown(false),
+ fDragging(false),
+ fDoubleClick(false),
+ fTrackingState(no_track),
+ fIsDropTarget(false),
+ fTitleEditView(NULL),
+ fPathWindow(NULL),
+ fLinkWindow(NULL),
+ fDescWindow(NULL),
+ fCurrentLinkColorWhich(B_LINK_TEXT_COLOR),
+ fCurrentPathColorWhich(fCurrentLinkColorWhich)
+{
+ // Set view color to standard background grey
+ SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
+ SetFont(be_plain_font);
+ // If the model is a symlink, then we deference the model to
+ // get the targets icon
+ if (fModel->IsSymLink()) {
+ Model* resolvedModel = new Model(model->EntryRef(), true, true);
+ if (resolvedModel->InitCheck() == B_OK)
+ fIconModel = resolvedModel;
+ // broken link, just show the symlink
+ else
+ delete resolvedModel;
+ }
+
+ // Create the rect for displaying the icon
+ fIconRect.Set(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1);
+ // Offset taken from BAlert
+ fIconRect.OffsetBy(kIconHorizOffset, kIconVertOffset);
+
+ // The title rect
+ // The magic numbers are used to properly calculate the rect so that
+ // when the editing text view is displayed, the position of the text
+ // does not change.
+ BFont currentFont;
+ font_height fontMetrics;
+ GetFont(¤tFont);
+ currentFont.GetHeight(&fontMetrics);
+
+ fTitleRect.left = fIconRect.right + 5;
+ fTitleRect.top = 0;
+ fTitleRect.bottom = fontMetrics.ascent + 1;
+ fTitleRect.right = min_c(
+ fTitleRect.left + currentFont.StringWidth(fModel->Name()),
+ Bounds().Width() - 5);
+ // Offset so that it centers with the icon
+ fTitleRect.OffsetBy(0,
+ fIconRect.top + ((fIconRect.Height() - fTitleRect.Height()) /
2));
+ // Make some room for the border for when we are in edit mode
+ // (Negative numbers increase the size of the rect)
+ fTitleRect.InsetBy(-1, -2);
+
+ fFreeBytes = -1;
+ fSizeString = "";
+ fSizeRect.Set(0, 0, 0, 0);
+
+ // Find offset for attributes, might be overiden below if there
+ // is a prefered handle menu displayed
+ currentFont.SetSize(currentFont.Size() - 2);
+ fDivider = currentFont.StringWidth(B_TRANSLATE("Description:"))
+ + kBorderMargin + kBorderWidth + 1;
+ // Add a preferred handler pop-up menu if this item
+ // is a file...This goes in place of the Link To:
+ // string...
+ if (model->IsFile()) {
+ BMimeType mime(fModel->MimeType());
+ BNodeInfo nodeInfo(fModel->Node());
+
+ // But don't add the menu if the file is executable
+ if (!fModel->IsExecutable()) {
+ float lineHeight = CurrentFontHeight();
+
+ BRect preferredAppRect(kBorderWidth + kBorderMargin,
+ fTitleRect.bottom + (lineHeight * 7),
+ Bounds().Width() - 5, fTitleRect.bottom +
(lineHeight * 8));
+ fPreferredAppMenu = new BMenuField(preferredAppRect,
"", "",
+ new BPopUpMenu(""));
+ currentFont.SetSize(currentFont.Size() + 2);
+ fDivider = currentFont.StringWidth(B_TRANSLATE("Opens
with:"))
+ + 5;
+ fPreferredAppMenu->SetDivider(fDivider);
+ fDivider += (preferredAppRect.left - 2);
+ fPreferredAppMenu->SetFont(¤tFont);
+ fPreferredAppMenu->SetHighUIColor(B_PANEL_TEXT_COLOR);
+ fPreferredAppMenu->SetLabel(B_TRANSLATE("Opens with:"));
+
+ char prefSignature[B_MIME_TYPE_LENGTH];
+ nodeInfo.GetPreferredApp(prefSignature);
+
+ BMessage supportingAppList;
+ mime.GetSupportingApps(&supportingAppList);
+
+ // Add the default menu item and set it to marked
+ BMenuItem* result;
+ result = new BMenuItem(B_TRANSLATE("Default
application"),
+ new BMessage(kSetPreferredApp));
+ result->SetTarget(this);
+ fPreferredAppMenu->Menu()->AddItem(result);
+ result->SetMarked(true);
+
+ for (int32 index = 0; ; index++) {
+ const char* signature;
+ if
(supportingAppList.FindString("applications", index,
+ &signature) != B_OK) {
+ break;
+ }
+
+ // Only add separator item if there are more
items
+ if (index == 0)
+
fPreferredAppMenu->Menu()->AddSeparatorItem();
+
+ BMessage* itemMessage = new
BMessage(kSetPreferredApp);
+ itemMessage->AddString("signature", signature);
+
+ status_t err = B_ERROR;
+ entry_ref entry;
+
+ if (signature && signature[0])
+ err = be_roster->FindApp(signature,
&entry);
+
+ if (err != B_OK)
+ result = new BMenuItem(signature,
itemMessage);
+ else
+ result = new BMenuItem(entry.name,
itemMessage);
+
+ result->SetTarget(this);
+ fPreferredAppMenu->Menu()->AddItem(result);
+ if (strcmp(signature, prefSignature) == 0)
+ result->SetMarked(true);
+ }
+
+ AddChild(fPreferredAppMenu);
+ }
+ }
+
+ fPermissionsSwitch = new PaneSwitch(BRect(), "Permissions");
+ fPermissionsSwitch->SetMessage(new BMessage(kPermissionsSelected));
+ fPermissionsSwitch->SetLabels(NULL, B_TRANSLATE("Permissions"));
+ AddChild(fPermissionsSwitch);
+ fPermissionsSwitch->ResizeToPreferred();
+ fPermissionsSwitch->MoveTo(kBorderWidth + 3,
+ Bounds().bottom - 3 - fPermissionsSwitch->Bounds().Height());
+
+ InitStrings(model);
+}
+
+
+GeneralInfoView::~GeneralInfoView()
+{
+ if (fPathWindow->Lock())
+ fPathWindow->Quit();
+
+ if (fLinkWindow->Lock())
+ fLinkWindow->Quit();
+
+ if (fDescWindow->Lock())
+ fDescWindow->Quit();
+
+ if (fIconModel != fModel)
+ delete fIconModel;
+}
+
+
+void
+GeneralInfoView::InitStrings(const Model* model)
+{
+ BMimeType mime;
+ char kind[B_MIME_TYPE_LENGTH];
+
+ ASSERT(model->IsNodeOpen());
+
+ BRect drawBounds(Bounds());
+ drawBounds.left = fDivider;
+
+ // We'll do our own truncation later on in Draw()
+ WidgetAttributeText::AttrAsString(model, &fCreatedStr, kAttrStatCreated,
+ B_TIME_TYPE, drawBounds.Width() - kBorderMargin, this);
+ WidgetAttributeText::AttrAsString(model, &fModifiedStr,
kAttrStatModified,
+ B_TIME_TYPE, drawBounds.Width() - kBorderMargin, this);
+ WidgetAttributeText::AttrAsString(model, &fPathStr, kAttrPath,
+ B_STRING_TYPE, 0, this);
+
+ // Use the same method as used to resolve fIconModel, which handles
+ // both absolute and relative symlinks. if the link is broken, try to
+ // get a little more information.
+ if (model->IsSymLink()) {
+ bool linked = false;
+
+ Model resolvedModel(model->EntryRef(), true, true);
+ if (resolvedModel.InitCheck() == B_OK) {
+ // Get the path of the link
+ BPath traversedPath;
+ resolvedModel.GetPath(&traversedPath);
+
+ // If the BPath is initialized, then check the file for
existence
+ if (traversedPath.InitCheck() == B_OK) {
+ BEntry entry(traversedPath.Path(), false);
+ // look at the target itself
+ if (entry.InitCheck() == B_OK && entry.Exists())
+ linked = true;
+ }
+ }
+
+ // always show the target as it is: absolute or relative!
+ BSymLink symLink(model->EntryRef());
+ char linkToPath[B_PATH_NAME_LENGTH];
+ symLink.ReadLink(linkToPath, B_PATH_NAME_LENGTH);
+ fLinkToStr = linkToPath;
+ if (!linked) {
+ // link points to missing object
+ fLinkToStr += B_TRANSLATE(" (broken)");
+ }
+ } else if (model->IsExecutable()) {
+ if (((Model*)model)->GetLongVersionString(fDescStr,
+ B_APP_VERSION_KIND) == B_OK) {
+ // we want a flat string, so replace all newlines and
tabs
+ // with spaces
+ fDescStr.ReplaceAll('\n', ' ');
+ fDescStr.ReplaceAll('\t', ' ');
+ } else
+ fDescStr = "-";
+ }
+
+ if (mime.SetType(model->MimeType()) == B_OK
+ && mime.GetShortDescription(kind) == B_OK)
+ fKindStr = kind;
+
+ if (fKindStr.Length() == 0)
+ fKindStr = model->MimeType();
+}
+
+
+void
+GeneralInfoView::AttachedToWindow()
+{
+ BFont font(be_plain_font);
+
+ font.SetSpacing(B_BITMAP_SPACING);
+ SetFont(&font);
+
+ CheckAndSetSize();
+ if (fPreferredAppMenu)
+ fPreferredAppMenu->Menu()->SetTargetForItems(this);
+
+ _inherited::AttachedToWindow();
+}
+
+
+void
+GeneralInfoView::Pulse()
+{
+ CheckAndSetSize();
+ _inherited::Pulse();
+}
+
+
+void
+GeneralInfoView::ModelChanged(Model* model, BMessage* message)
+{
+ BRect drawBounds(Bounds());
+ drawBounds.left = fDivider;
+
+ switch (message->FindInt32("opcode")) {
+ case B_ENTRY_MOVED:
+ {
+ node_ref dirNode;
+ node_ref itemNode;
+ dirNode.device = itemNode.device =
message->FindInt32("device");
+ message->FindInt64("to directory", &dirNode.node);
+ message->FindInt64("node", &itemNode.node);
+
+ const char* name;
+ if (message->FindString("name", &name) != B_OK)
+ return;
+
+ // ensure notification is for us
+ if (*model->NodeRef() == itemNode
+ // For volumes, the device ID is obviously not
handled in a
+ // consistent way; the node monitor sends us
the ID of the
+ // parent device, while the model is set to the
device of the
+ // volume directly - this hack works for
volumes that are
+ // mounted in the root directory
+ || (model->IsVolume()
+ && itemNode.device == 1
+ && itemNode.node ==
model->NodeRef()->node)) {
+ model->UpdateEntryRef(&dirNode, name);
+ BString title;
+ title << name << B_TRANSLATE(" info");
+ Window()->SetTitle(title.String());
+ WidgetAttributeText::AttrAsString(model,
&fPathStr, kAttrPath,
+ B_STRING_TYPE, 0, this);
+ Invalidate();
+ }
+ break;
+ }
+
+ case B_STAT_CHANGED:
+ if (model->OpenNode() == B_OK) {
+ WidgetAttributeText::AttrAsString(model,
&fCreatedStr,
+ kAttrStatCreated, B_TIME_TYPE,
drawBounds.Width()
+ - kBorderMargin, this);
+ WidgetAttributeText::AttrAsString(model,
&fModifiedStr,
+ kAttrStatModified, B_TIME_TYPE,
drawBounds.Width()
+ - kBorderMargin, this);
+
+ // don't change the size if it's a directory
+ if (!model->IsDirectory()) {
+ fLastSize = model->StatBuf()->st_size;
+ fSizeString = "";
+ BInfoWindow::GetSizeString(fSizeString,
fLastSize, 0);
+ }
+ model->CloseNode();
+ }
+ break;
+
+ case B_ATTR_CHANGED:
+ {
+ // watch for icon updates
+ const char* attrName;
+ if (message->FindString("attr", &attrName) == B_OK) {
+ if (strcmp(attrName, kAttrLargeIcon) == 0
+ || strcmp(attrName, kAttrIcon) == 0) {
+
IconCache::sIconCache->IconChanged(model->ResolveIfLink());
+ Invalidate();
+ } else if (strcmp(attrName, kAttrMIMEType) ==
0) {
+ if (model->OpenNode() == B_OK) {
+ model->AttrChanged(attrName);
+ InitStrings(model);
+ model->CloseNode();
+ }
+ Invalidate();
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Update the icon stuff
+ if (fIconModel != fModel) {
+ delete fIconModel;
+ fIconModel = NULL;
+ }
+
+ fModel = model;
+ if (fModel->IsSymLink()) {
+ // if we are looking at a symlink, deference the model and look
+ // at the target
+ Model* resolvedModel = new Model(model->EntryRef(), true, true);
+ if (resolvedModel->InitCheck() == B_OK) {
+ if (fIconModel != fModel)
+ delete fIconModel;
+ fIconModel = resolvedModel;
+ } else {
+ fIconModel = model;
+ delete resolvedModel;
+ }
+ InitStrings(model);
+ Invalidate();
+ }
+
+ drawBounds.left = fDivider;
+ Invalidate(drawBounds);
+}
+
+
+// This only applies to symlinks. If the target of the symlink
+// was changed, then we have to update the entire model.
+// (Since in order to re-target a symlink, we had to delete
+// the old model and create a new one; BSymLink::SetTarget(),
+// would be nice)
+
+void
+GeneralInfoView::ReLinkTargetModel(Model* model)
+{
+ fModel = model;
+ if (fModel->IsSymLink()) {
+ Model* resolvedModel = new Model(model->EntryRef(), true, true);
+ if (resolvedModel->InitCheck() == B_OK) {
+ if (fIconModel != fModel)
+ delete fIconModel;
+ fIconModel = resolvedModel;
+ } else {
+ fIconModel = fModel;
+ delete resolvedModel;
+ }
+ }
+ InitStrings(model);
+ Invalidate(Bounds());
+}
+
+
+void
+GeneralInfoView::MouseDown(BPoint where)
+{
+ BEntry entry;
+ fModel->GetEntry(&entry);
+
+ // Assume this isn't part of a double click
+ fDoubleClick = false;
+
+ // Start tracking the mouse if we are in any of the hotspots
+ if (fLinkRect.Contains(where)) {
+ InvertRect(fLinkRect);
+ fTrackingState = link_track;
+ } else if (fPathRect.Contains(where)) {
+ InvertRect(fPathRect);
+ fTrackingState = path_track;
+ } else if (fTitleRect.Contains(where)) {
+ if (!fModel->HasLocalizedName()
+ && ConfirmChangeIfWellKnownDirectory(&entry, kRename,
true)) {
+ BeginEditingTitle();
+ }
+ } else if (fTitleEditView) {
+ FinishEditingTitle(true);
+ } else if (fSizeRect.Contains(where)) {
+ if (fModel->IsDirectory() && !fModel->IsVolume()
+ && !fModel->IsRoot()) {
+ InvertRect(fSizeRect);
+ fTrackingState = size_track;
+ } else
+ fTrackingState = no_track;
+ } else if (fIconRect.Contains(where)) {
+ uint32 buttons;
+ Window()->CurrentMessage()->FindInt32("buttons",
(int32*)&buttons);
+ if (SecondaryMouseButtonDown(modifiers(), buttons)) {
+ // Show contextual menu
+ BPopUpMenu* contextMenu
+ = new BPopUpMenu("FileContext", false, false);
+ if (contextMenu) {
+ BuildContextMenu(contextMenu);
+ contextMenu->SetAsyncAutoDestruct(true);
+ contextMenu->Go(ConvertToScreen(where), true,
true,
+ ConvertToScreen(fIconRect));
+ }
+ } else {
+ // Check to see if the point is actually on part of the
icon,
+ // versus just in the container rect. The icons are
always
+ // the large version
+ BPoint offsetPoint;
+ offsetPoint.x = where.x - fIconRect.left;
+ offsetPoint.y = where.y - fIconRect.top;
+ if (IconCache::sIconCache->IconHitTest(offsetPoint,
fIconModel,
+ kNormalIcon, B_LARGE_ICON)) {
+ // Can't drag the trash anywhere..
+ fTrackingState = fModel->IsTrash()
+ ? open_only_track : icon_track;
+
+ // Check for possible double click
+ if (abs((int32)(fClickPoint.x - where.x)) <
kDragSlop
+ && abs((int32)(fClickPoint.y -
where.y)) < kDragSlop) {
+ int32 clickCount;
+
Window()->CurrentMessage()->FindInt32("clicks",
+ &clickCount);
+
+ // This checks the* previous* click
point
+ if (clickCount == 2) {
+ offsetPoint.x = fClickPoint.x -
fIconRect.left;
+ offsetPoint.y = fClickPoint.y -
fIconRect.top;
+ fDoubleClick
+ =
IconCache::sIconCache->IconHitTest(offsetPoint,
+ fIconModel,
kNormalIcon, B_LARGE_ICON);
+ }
+ }
+ }
+ }
+ }
+
+ fClickPoint = where;
+ fMouseDown = true;
+ SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
+}
+
+
+void
+GeneralInfoView::MouseMoved(BPoint where, uint32, const BMessage* dragMessage)
+{
+ if (dragMessage != NULL && dragMessage->ReturnAddress() !=
BMessenger(this)
+ && dragMessage->what == B_SIMPLE_DATA
+ && BPoseView::CanHandleDragSelection(fModel, dragMessage,
+ (modifiers() & B_CONTROL_KEY) != 0)) {
+ // highlight drag target
+ bool overTarget = fIconRect.Contains(where);
+ SetDrawingMode(B_OP_OVER);
+ if (overTarget != fIsDropTarget) {
+ IconCache::sIconCache->Draw(fIconModel, this,
fIconRect.LeftTop(),
+ overTarget ? kSelectedIcon : kNormalIcon,
B_LARGE_ICON, true);
+ fIsDropTarget = overTarget;
+ }
+ }
+
+ fCurrentLinkColorWhich = B_LINK_TEXT_COLOR;
+ fCurrentPathColorWhich = fCurrentLinkColorWhich;
+
+ switch (fTrackingState) {
+ case link_track:
+ if (fLinkRect.Contains(where) != fMouseDown) {
+ fMouseDown = !fMouseDown;
+ InvertRect(fLinkRect);
+ }
+ break;
+
+ case path_track:
+ if (fPathRect.Contains(where) != fMouseDown) {
+ fMouseDown = !fMouseDown;
+ InvertRect(fPathRect);
+ }
+ break;
+
+ case size_track:
+ if (fSizeRect.Contains(where) != fMouseDown) {
+ fMouseDown = !fMouseDown;
+ InvertRect(fSizeRect);
+ }
+ break;
+
+ case icon_track:
+ if (fMouseDown && !fDragging
+ && (abs((int32)(where.x - fClickPoint.x)) >
kDragSlop
+ || abs((int32)(where.y -
fClickPoint.y)) > kDragSlop)) {
+ // Find the required height
+ BFont font;
+ GetFont(&font);
+
+ float height = CurrentFontHeight()
+ + fIconRect.Height() + 8;
+ BRect rect(0, 0, min_c(fIconRect.Width()
+ +
font.StringWidth(fModel->Name()) + 4,
+ fIconRect.Width() * 3), height);
+ BBitmap* dragBitmap = new BBitmap(rect,
B_RGBA32, true);
+ dragBitmap->Lock();
+ BView* view = new BView(dragBitmap->Bounds(),
"",
+ B_FOLLOW_NONE, 0);
+ dragBitmap->AddChild(view);
+ view->SetOrigin(0, 0);
+ BRect clipRect(view->Bounds());
+ BRegion newClip;
+ newClip.Set(clipRect);
+ view->ConstrainClippingRegion(&newClip);
+
+ // Transparent draw magic
+ view->SetHighColor(0, 0, 0, 0);
+ view->FillRect(view->Bounds());
+ view->SetDrawingMode(B_OP_ALPHA);
+ rgb_color textColor =
ui_color(B_PANEL_TEXT_COLOR);
+ textColor.alpha = 128;
+ // set transparency by value
+ view->SetHighColor(textColor);
+ view->SetBlendingMode(B_CONSTANT_ALPHA,
B_ALPHA_COMPOSITE);
+
+ // Draw the icon
+ float hIconOffset = (rect.Width() -
fIconRect.Width()) / 2;
+ IconCache::sIconCache->Draw(fIconModel, view,
+ BPoint(hIconOffset, 0), kNormalIcon,
B_LARGE_ICON, true);
+
+ // See if we need to truncate the string
+ BString nameString(fModel->Name());
+ if (view->StringWidth(fModel->Name()) >
rect.Width()) {
+ view->TruncateString(&nameString,
B_TRUNCATE_END,
+ rect.Width() - 5);
+ }
+
+ // Draw the label
+ font_height fontHeight;
+ font.GetHeight(&fontHeight);
+ float leftText =
(view->StringWidth(nameString.String())
+ - fIconRect.Width()) / 2;
+ view->MovePenTo(BPoint(hIconOffset - leftText +
2,
+ fIconRect.Height() + (fontHeight.ascent
+ 2)));
+ view->DrawString(nameString.String());
+
+ view->Sync();
+ dragBitmap->Unlock();
+
+ BMessage dragMessage(B_REFS_RECEIVED);
+ dragMessage.AddPoint("click_pt", fClickPoint);
+ BPoint tmpLoc;
+ uint32 button;
+ GetMouse(&tmpLoc, &button);
+ if (button)
+ dragMessage.AddInt32("buttons",
(int32)button);
+
+ dragMessage.AddInt32("be:actions",
+ (modifiers() & B_OPTION_KEY) != 0
+ ? B_COPY_TARGET :
B_MOVE_TARGET);
+ dragMessage.AddRef("refs", fModel->EntryRef());
+ DragMessage(&dragMessage, dragBitmap,
B_OP_ALPHA,
+ BPoint((fClickPoint.x - fIconRect.left)
+ + hIconOffset, fClickPoint.y -
fIconRect.top), this);
+ fDragging = true;
+ }
+ break;
+
+ case open_only_track :
+ // Special type of entry that can't be renamed or drag
and dropped
+ // It can only be opened by double clicking on the icon
+ break;
+
+ default:
+ {
+ // Only consider this if the window is the active
window.
+ // We have to manually get the mouse here in the event
that the
+ // mouse is over a pop-up window
+ uint32 buttons;
+ BPoint point;
+ GetMouse(&point, &buttons);
+ if (Window()->IsActive() && !buttons) {
+ // If we are down here, then that means that
we're tracking
+ // the mouse but not from a mouse down. In this
case, we're
+ // just interested in knowing whether or not we
need to
+ // display the "pop-up" version of the path or
link text.
+ BScreen screen(Window());
+ BFont font;
+ GetFont(&font);
+ float maxWidth = (Bounds().Width()
+ - (fDivider + kBorderMargin));
+
+ if (fPathRect.Contains(point)) {
+ if (fCurrentPathColorWhich !=
B_LINK_HOVER_COLOR)
+ fCurrentPathColorWhich =
B_LINK_HOVER_COLOR;
+
+ if (font.StringWidth(fPathStr.String())
maxWidth) {+ fTrackingState = no_track;
maxWidth) {+ fTrackingState = no_track;