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 <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
ebb30434c9
commit
2140520f96
@@ -46,6 +46,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
||||
FindPanel.cpp
|
||||
GeneralInfoView.cpp
|
||||
GroupedMenu.cpp
|
||||
HeaderView.cpp
|
||||
IconCache.cpp
|
||||
IconMenuItem.cpp
|
||||
InfoWindow.cpp
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
|
||||
FilePermissionsView::FilePermissionsView(BRect rect, Model* model)
|
||||
:
|
||||
BView(rect, "FilePermissionsView", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
|
||||
BView(rect, B_TRANSLATE("Permissions"), B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
|
||||
fModel(model)
|
||||
{
|
||||
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
|
||||
|
||||
@@ -35,7 +35,8 @@ All rights reserved.
|
||||
|
||||
#include "GeneralInfoView.h"
|
||||
|
||||
#include <Alert.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Catalog.h>
|
||||
#include <Locale.h>
|
||||
@@ -44,7 +45,6 @@ All rights reserved.
|
||||
#include <Region.h>
|
||||
#include <Roster.h>
|
||||
#include <Screen.h>
|
||||
#include <ScrollView.h>
|
||||
#include <StringFormat.h>
|
||||
#include <SymLink.h>
|
||||
#include <Volume.h>
|
||||
@@ -87,16 +87,9 @@ private:
|
||||
} // 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';
|
||||
@@ -158,76 +151,46 @@ OpenToolTipWindow(BScreen& screen, BRect rect, const char* name,
|
||||
}
|
||||
|
||||
|
||||
GeneralInfoView::GeneralInfoView(BRect rect, Model* model)
|
||||
GeneralInfoView::GeneralInfoView(Model* model)
|
||||
:
|
||||
BView(rect, "attr_view", B_FOLLOW_ALL_SIDES,
|
||||
B_WILL_DRAW | B_PULSE_NEEDED),
|
||||
BGroupView(B_VERTICAL),
|
||||
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)
|
||||
{
|
||||
SetFlags(Flags() | B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS);
|
||||
SetName(B_TRANSLATE("Information"));
|
||||
// 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
|
||||
BFont currentFont;
|
||||
GetFont(¤tFont);
|
||||
currentFont.SetSize(currentFont.Size() - 2);
|
||||
fDivider = currentFont.StringWidth(B_TRANSLATE("Description:"))
|
||||
+ kBorderMargin + kBorderWidth + 1;
|
||||
|
||||
// The widest string depends on the locale. We should check them all, this
|
||||
// is only an approximation that works for English and French.
|
||||
float width = currentFont.StringWidth(B_TRANSLATE("Description:"));
|
||||
width = std::max(width, currentFont.StringWidth(B_TRANSLATE("Location:")));
|
||||
fDivider = width + kBorderMargin + 1;
|
||||
|
||||
// Keep some free space for the stuff we print ourselves
|
||||
float lineHeight = CurrentFontHeight();
|
||||
GroupLayout()->SetInsets(kBorderMargin, lineHeight * 7,
|
||||
B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING);
|
||||
|
||||
// Add a preferred handler pop-up menu if this item
|
||||
// is a file...This goes in place of the Link To:
|
||||
// string...
|
||||
@@ -237,18 +200,12 @@ GeneralInfoView::GeneralInfoView(BRect rect, Model* model)
|
||||
|
||||
// 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(""));
|
||||
fPreferredAppMenu = new BMenuField("", "", new BPopUpMenu(""));
|
||||
currentFont.SetSize(currentFont.Size() + 2);
|
||||
fDivider = currentFont.StringWidth(B_TRANSLATE("Opens with:"))
|
||||
+ 5;
|
||||
fPreferredAppMenu->SetDivider(fDivider);
|
||||
fDivider += (preferredAppRect.left - 2);
|
||||
fDivider += (kBorderMargin - 2);
|
||||
fPreferredAppMenu->SetFont(¤tFont);
|
||||
fPreferredAppMenu->SetHighUIColor(B_PANEL_TEXT_COLOR);
|
||||
fPreferredAppMenu->SetLabel(B_TRANSLATE("Opens with:"));
|
||||
@@ -301,16 +258,6 @@ GeneralInfoView::GeneralInfoView(BRect rect, Model* model)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -324,9 +271,6 @@ GeneralInfoView::~GeneralInfoView()
|
||||
|
||||
if (fDescWindow->Lock())
|
||||
fDescWindow->Quit();
|
||||
|
||||
if (fIconModel != fModel)
|
||||
delete fIconModel;
|
||||
}
|
||||
|
||||
|
||||
@@ -507,25 +451,8 @@ GeneralInfoView::ModelChanged(Model* model, BMessage* message)
|
||||
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();
|
||||
}
|
||||
@@ -545,17 +472,6 @@ 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());
|
||||
}
|
||||
@@ -564,12 +480,6 @@ GeneralInfoView::ReLinkTargetModel(Model* model)
|
||||
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);
|
||||
@@ -577,67 +487,14 @@ GeneralInfoView::MouseDown(BPoint where)
|
||||
} 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);
|
||||
}
|
||||
@@ -646,20 +503,6 @@ GeneralInfoView::MouseDown(BPoint where)
|
||||
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;
|
||||
|
||||
@@ -685,88 +528,6 @@ GeneralInfoView::MouseMoved(BPoint where, uint32, const BMessage* dragMessage)
|
||||
}
|
||||
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.
|
||||
@@ -893,23 +654,6 @@ GeneralInfoView::MouseUp(BPoint where)
|
||||
} else if (fTrackingState == path_track && fPathRect.Contains(where)) {
|
||||
InvertRect(fPathRect);
|
||||
OpenLinkSource();
|
||||
} else if ((fTrackingState == icon_track
|
||||
|| fTrackingState == open_only_track)
|
||||
&& fIconRect.Contains(where)) {
|
||||
// If it was a double click, then tell Tracker to open the item
|
||||
// The CurrentMessage() here does* not* have a "clicks" field,
|
||||
// which is why we are tracking the clicks with this temp var
|
||||
if (fDoubleClick) {
|
||||
// Double click, launch.
|
||||
BMessage message(B_REFS_RECEIVED);
|
||||
message.AddRef("refs", fModel->EntryRef());
|
||||
|
||||
// add a messenger to the launch message that will be used to
|
||||
// dispatch scripting calls from apps to the PoseView
|
||||
message.AddMessenger("TrackerViewToken", BMessenger(this));
|
||||
be_app->PostMessage(&message);
|
||||
fDoubleClick = false;
|
||||
}
|
||||
} else if (fTrackingState == size_track && fSizeRect.Contains(where)) {
|
||||
// Recalculate size
|
||||
Window()->PostMessage(kRecalculateSize);
|
||||
@@ -917,9 +661,7 @@ GeneralInfoView::MouseUp(BPoint where)
|
||||
|
||||
// End mouse tracking
|
||||
fMouseDown = false;
|
||||
fDragging = false;
|
||||
fTrackingState = no_track;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -981,8 +723,7 @@ GeneralInfoView::CheckAndSetSize()
|
||||
|
||||
BRect bounds(Bounds());
|
||||
float lineHeight = CurrentFontHeight() + 2;
|
||||
bounds.Set(fDivider, fIconRect.bottom, bounds.right,
|
||||
fIconRect.bottom + lineHeight);
|
||||
bounds.Set(fDivider, 0, bounds.right, lineHeight);
|
||||
Invalidate(bounds);
|
||||
}
|
||||
|
||||
@@ -990,18 +731,6 @@ GeneralInfoView::CheckAndSetSize()
|
||||
void
|
||||
GeneralInfoView::MessageReceived(BMessage* message)
|
||||
{
|
||||
if (message->WasDropped()
|
||||
&& message->what == B_SIMPLE_DATA
|
||||
&& message->ReturnAddress() != BMessenger(this)
|
||||
&& fIconRect.Contains(ConvertFromScreen(message->DropPoint()))
|
||||
&& BPoseView::CanHandleDragSelection(fModel, message,
|
||||
(modifiers() & B_CONTROL_KEY) != 0)) {
|
||||
BPoseView::HandleDropCommon(message, fModel, 0, this,
|
||||
message->DropPoint());
|
||||
Invalidate(fIconRect);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message->what) {
|
||||
case kSetPreferredApp:
|
||||
{
|
||||
@@ -1032,6 +761,16 @@ GeneralInfoView::MessageReceived(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::FrameResized(float, float)
|
||||
{
|
||||
BModelOpener opener(fModel);
|
||||
|
||||
// Truncate the strings according to the new width
|
||||
InitStrings(fModel);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::Draw(BRect)
|
||||
{
|
||||
@@ -1045,54 +784,17 @@ GeneralInfoView::Draw(BRect)
|
||||
rgb_color labelColor = ui_color(B_PANEL_TEXT_COLOR);
|
||||
rgb_color attributeColor = mix_color(HighColor(), labelColor, 192);
|
||||
|
||||
// Draw the dark grey area on the left
|
||||
BRect drawBounds(Bounds());
|
||||
drawBounds.right = kBorderWidth;
|
||||
SetHighUIColor(B_PANEL_BACKGROUND_COLOR, B_DARKEN_2_TINT);
|
||||
FillRect(drawBounds);
|
||||
|
||||
// Draw the icon, straddling the border
|
||||
SetDrawingMode(B_OP_OVER);
|
||||
IconCache::sIconCache->Draw(fIconModel, this, fIconRect.LeftTop(),
|
||||
kNormalIcon, B_LARGE_ICON, true);
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
// Font information
|
||||
font_height fontMetrics;
|
||||
BFont currentFont;
|
||||
float lineHeight = 0;
|
||||
float lineBase = 0;
|
||||
// Draw the main title if the user is not currently editing it
|
||||
if (fTitleEditView == NULL) {
|
||||
SetFont(be_bold_font);
|
||||
SetFontSize(be_bold_font->Size());
|
||||
GetFont(¤tFont);
|
||||
currentFont.GetHeight(&fontMetrics);
|
||||
lineHeight = CurrentFontHeight() + 5;
|
||||
lineBase = fTitleRect.bottom - fontMetrics.descent;
|
||||
SetHighColor(labelColor);
|
||||
MovePenTo(BPoint(fIconRect.right + 6, lineBase));
|
||||
|
||||
// Recalculate the rect width
|
||||
fTitleRect.right = min_c(
|
||||
fTitleRect.left + currentFont.StringWidth(fModel->Name()),
|
||||
Bounds().Width() - 5);
|
||||
// Check for possible need of truncation
|
||||
if (StringWidth(fModel->Name()) > fTitleRect.Width()) {
|
||||
BString nameString(fModel->Name());
|
||||
TruncateString(&nameString, B_TRUNCATE_END,
|
||||
fTitleRect.Width() - 2);
|
||||
DrawString(nameString.String());
|
||||
} else
|
||||
DrawString(fModel->Name());
|
||||
}
|
||||
|
||||
// Draw the attribute font stuff
|
||||
SetFont(be_plain_font);
|
||||
GetFontHeight(&fontMetrics);
|
||||
lineHeight = CurrentFontHeight() + 5;
|
||||
|
||||
// Starting base line for the first string
|
||||
lineBase = fTitleRect.bottom + lineHeight;
|
||||
lineBase = lineHeight;
|
||||
|
||||
// Capacity/size
|
||||
SetHighColor(labelColor);
|
||||
@@ -1258,128 +960,12 @@ GeneralInfoView::Draw(BRect)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::BeginEditingTitle()
|
||||
{
|
||||
if (fTitleEditView != NULL)
|
||||
return;
|
||||
|
||||
BFont font(be_plain_font);
|
||||
font.SetSize(font.Size() + 2);
|
||||
BRect textFrame(fTitleRect);
|
||||
textFrame.right = Bounds().Width() - 5;
|
||||
BRect textRect(textFrame);
|
||||
textRect.OffsetTo(0, 0);
|
||||
textRect.InsetBy(1, 1);
|
||||
|
||||
// Just make it some really large size, since we don't do any line
|
||||
// wrapping. The text filter will make sure to scroll the cursor
|
||||
// into position
|
||||
|
||||
textRect.right = 2000;
|
||||
fTitleEditView = new BTextView(textFrame, "text_editor",
|
||||
textRect, &font, 0, B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
fTitleEditView->SetText(fModel->Name());
|
||||
DisallowFilenameKeys(fTitleEditView);
|
||||
|
||||
// Reset the width of the text rect
|
||||
textRect = fTitleEditView->TextRect();
|
||||
textRect.right = fTitleEditView->LineWidth() + 20;
|
||||
fTitleEditView->SetTextRect(textRect);
|
||||
fTitleEditView->SetWordWrap(false);
|
||||
// Add filter for catching B_RETURN and B_ESCAPE key's
|
||||
fTitleEditView->AddFilter(
|
||||
new BMessageFilter(B_KEY_DOWN, GeneralInfoView::TextViewFilter));
|
||||
|
||||
BScrollView* scrollView = new BScrollView("BorderView", fTitleEditView,
|
||||
0, 0, false, false, B_PLAIN_BORDER);
|
||||
AddChild(scrollView);
|
||||
fTitleEditView->SelectAll();
|
||||
fTitleEditView->MakeFocus();
|
||||
|
||||
Window()->UpdateIfNeeded();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::FinishEditingTitle(bool commit)
|
||||
{
|
||||
if (fTitleEditView == NULL)
|
||||
return;
|
||||
|
||||
bool reopen = false;
|
||||
|
||||
const char* text = fTitleEditView->Text();
|
||||
uint32 length = strlen(text);
|
||||
if (commit && strcmp(text, fModel->Name()) != 0
|
||||
&& length < B_FILE_NAME_LENGTH) {
|
||||
BEntry entry(fModel->EntryRef());
|
||||
BDirectory parent;
|
||||
if (entry.InitCheck() == B_OK
|
||||
&& entry.GetParent(&parent) == B_OK) {
|
||||
if (parent.Contains(text)) {
|
||||
BAlert* alert = new BAlert("",
|
||||
B_TRANSLATE("That name is already taken. "
|
||||
"Please type another one."),
|
||||
B_TRANSLATE("OK"),
|
||||
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go();
|
||||
reopen = true;
|
||||
} else {
|
||||
if (fModel->IsVolume()) {
|
||||
BVolume volume(fModel->NodeRef()->device);
|
||||
if (volume.InitCheck() == B_OK)
|
||||
volume.SetName(text);
|
||||
} else
|
||||
entry.Rename(text);
|
||||
|
||||
// Adjust the size of the text rect
|
||||
BFont currentFont(be_plain_font);
|
||||
currentFont.SetSize(currentFont.Size() + 2);
|
||||
fTitleRect.right = min_c(fTitleRect.left
|
||||
+ currentFont.StringWidth(fTitleEditView->Text()),
|
||||
Bounds().Width() - 5);
|
||||
}
|
||||
}
|
||||
} else if (length >= B_FILE_NAME_LENGTH) {
|
||||
BAlert* alert = new BAlert("",
|
||||
B_TRANSLATE("That name is too long. Please type another one."),
|
||||
B_TRANSLATE("OK"),
|
||||
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go();
|
||||
reopen = true;
|
||||
}
|
||||
|
||||
// Remove view
|
||||
BView* scrollView = fTitleEditView->Parent();
|
||||
RemoveChild(scrollView);
|
||||
delete scrollView;
|
||||
fTitleEditView = NULL;
|
||||
|
||||
if (reopen)
|
||||
BeginEditingTitle();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::MakeFocus(bool focus)
|
||||
{
|
||||
if (!focus && fTitleEditView != NULL)
|
||||
FinishEditingTitle(true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::WindowActivated(bool active)
|
||||
{
|
||||
if (active)
|
||||
return;
|
||||
|
||||
if (fTitleEditView != NULL)
|
||||
FinishEditingTitle(true);
|
||||
|
||||
if (fPathWindow->Lock()) {
|
||||
fPathWindow->Quit();
|
||||
fPathWindow = NULL;
|
||||
@@ -1409,148 +995,6 @@ GeneralInfoView::CurrentFontHeight()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GeneralInfoView::BuildContextMenu(BMenu* parent)
|
||||
{
|
||||
if (parent == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// Add navigation menu if this is not a symlink
|
||||
// Symlink's to directories are OK however!
|
||||
BEntry entry(fModel->EntryRef());
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
Model model(&entry);
|
||||
bool navigate = false;
|
||||
if (model.InitCheck() == B_OK) {
|
||||
if (model.IsSymLink()) {
|
||||
// Check if it's to a directory
|
||||
if (entry.SetTo(model.EntryRef(), true) == B_OK) {
|
||||
navigate = entry.IsDirectory();
|
||||
entry.GetRef(&ref);
|
||||
}
|
||||
} else if (model.IsDirectory() || model.IsVolume())
|
||||
navigate = true;
|
||||
}
|
||||
ModelMenuItem* navigationItem = NULL;
|
||||
if (navigate) {
|
||||
navigationItem = new ModelMenuItem(new Model(model),
|
||||
new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, Window()));
|
||||
|
||||
// setup a navigation menu item which will dynamically load items
|
||||
// as menu items are traversed
|
||||
BNavMenu* navMenu = dynamic_cast<BNavMenu*>(navigationItem->Submenu());
|
||||
if (navMenu != NULL)
|
||||
navMenu->SetNavDir(&ref);
|
||||
|
||||
navigationItem->SetLabel(model.Name());
|
||||
navigationItem->SetEntry(&entry);
|
||||
|
||||
parent->AddItem(navigationItem, 0);
|
||||
parent->AddItem(new BSeparatorItem(), 1);
|
||||
|
||||
BMessage* message = new BMessage(B_REFS_RECEIVED);
|
||||
message->AddRef("refs", &ref);
|
||||
navigationItem->SetMessage(message);
|
||||
navigationItem->SetTarget(be_app);
|
||||
}
|
||||
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Open"),
|
||||
new BMessage(kOpenSelection), 'O'));
|
||||
|
||||
if (!model.IsDesktop() && !model.IsRoot() && !model.IsTrash()
|
||||
&& !fModel->HasLocalizedName()) {
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Edit name"),
|
||||
new BMessage(kEditItem), 'E'));
|
||||
parent->AddSeparatorItem();
|
||||
|
||||
if (fModel->IsVolume()) {
|
||||
BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"),
|
||||
new BMessage(kUnmountVolume), 'U');
|
||||
parent->AddItem(item);
|
||||
// volume model, enable/disable the Unmount item
|
||||
BVolume boot;
|
||||
BVolumeRoster().GetBootVolume(&boot);
|
||||
BVolume volume;
|
||||
volume.SetTo(fModel->NodeRef()->device);
|
||||
if (volume == boot)
|
||||
item->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!model.IsRoot() && !model.IsVolume() && !model.IsTrash())
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Identify"),
|
||||
new BMessage(kIdentifyEntry)));
|
||||
|
||||
if (model.IsTrash())
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"),
|
||||
new BMessage(kEmptyTrash)));
|
||||
|
||||
BMenuItem* sizeItem = NULL;
|
||||
if (model.IsDirectory() && !model.IsVolume() && !model.IsRoot()) {
|
||||
parent->AddItem(sizeItem
|
||||
= new BMenuItem(B_TRANSLATE("Recalculate folder size"),
|
||||
new BMessage(kRecalculateSize)));
|
||||
}
|
||||
|
||||
if (model.IsSymLink()) {
|
||||
parent->AddItem(sizeItem
|
||||
= new BMenuItem(B_TRANSLATE("Set new link target"),
|
||||
new BMessage(kSetLinkTarget)));
|
||||
}
|
||||
|
||||
parent->AddItem(new BSeparatorItem());
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Permissions"),
|
||||
new BMessage(kPermissionsSelected), 'P'));
|
||||
|
||||
parent->SetFont(be_plain_font);
|
||||
parent->SetTargetForItems(this);
|
||||
|
||||
// Reset the nav menu to be_app
|
||||
if (navigate)
|
||||
navigationItem->SetTarget(be_app);
|
||||
if (sizeItem)
|
||||
sizeItem->SetTarget(Window());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralInfoView::SetPermissionsSwitchState(int32 state)
|
||||
{
|
||||
fPermissionsSwitch->SetValue(state);
|
||||
fPermissionsSwitch->Invalidate();
|
||||
}
|
||||
|
||||
|
||||
filter_result
|
||||
GeneralInfoView::TextViewFilter(BMessage* message, BHandler**,
|
||||
BMessageFilter* filter)
|
||||
{
|
||||
uchar key;
|
||||
GeneralInfoView* attribView = static_cast<GeneralInfoView*>(
|
||||
static_cast<BWindow*>(filter->Looper())->FindView("attr_view"));
|
||||
|
||||
// Adjust the size of the text rect
|
||||
BRect nuRect(attribView->TextView()->TextRect());
|
||||
nuRect.right = attribView->TextView()->LineWidth() + 20;
|
||||
attribView->TextView()->SetTextRect(nuRect);
|
||||
|
||||
// Make sure the cursor is in view
|
||||
attribView->TextView()->ScrollToSelection();
|
||||
if (message->FindInt8("byte", (int8*)&key) != B_OK)
|
||||
return B_DISPATCH_MESSAGE;
|
||||
|
||||
if (key == B_RETURN || key == B_ESCAPE) {
|
||||
attribView->FinishEditingTitle(key == B_RETURN);
|
||||
return B_SKIP_MESSAGE;
|
||||
}
|
||||
|
||||
return B_DISPATCH_MESSAGE;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
GeneralInfoView::LastSize() const
|
||||
{
|
||||
@@ -1572,8 +1016,7 @@ GeneralInfoView::SetSizeString(const char* sizeString)
|
||||
|
||||
BRect bounds(Bounds());
|
||||
float lineHeight = CurrentFontHeight() + 6;
|
||||
bounds.Set(fDivider, fIconRect.bottom, bounds.right,
|
||||
fIconRect.bottom + lineHeight);
|
||||
bounds.Set(fDivider, 0, bounds.right, lineHeight);
|
||||
Invalidate(bounds);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ All rights reserved.
|
||||
#define GENERALINFOVIEW_H
|
||||
|
||||
|
||||
#include <GroupView.h>
|
||||
#include <MenuField.h>
|
||||
#include <Message.h>
|
||||
#include <Rect.h>
|
||||
#include <TextView.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "DialogPane.h"
|
||||
#include "Model.h"
|
||||
@@ -53,48 +53,33 @@ enum track_state {
|
||||
no_track = 0,
|
||||
link_track,
|
||||
path_track,
|
||||
icon_track,
|
||||
size_track,
|
||||
open_only_track
|
||||
// This is for items that can be opened, but can't be
|
||||
// drag and dropped or renamed (Trash, Desktop Folder...)
|
||||
};
|
||||
|
||||
|
||||
class GeneralInfoView : public BView {
|
||||
class GeneralInfoView : public BGroupView {
|
||||
public:
|
||||
GeneralInfoView(BRect, Model*);
|
||||
GeneralInfoView(Model*);
|
||||
~GeneralInfoView();
|
||||
|
||||
void ModelChanged(Model*, BMessage*);
|
||||
void ReLinkTargetModel(Model*);
|
||||
void BeginEditingTitle();
|
||||
void FinishEditingTitle(bool);
|
||||
float CurrentFontHeight();
|
||||
|
||||
BTextView* TextView() const { return fTitleEditView; }
|
||||
|
||||
static filter_result TextViewFilter(BMessage*, BHandler**,
|
||||
BMessageFilter*);
|
||||
|
||||
off_t LastSize() const;
|
||||
void SetLastSize(off_t);
|
||||
|
||||
void SetSizeString(const char*);
|
||||
|
||||
status_t BuildContextMenu(BMenu* parent);
|
||||
|
||||
void SetPermissionsSwitchState(int32 state);
|
||||
|
||||
protected:
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32, const BMessage* dragMessage);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void AttachedToWindow();
|
||||
virtual void FrameResized(float, float);
|
||||
virtual void Draw(BRect);
|
||||
virtual void Pulse();
|
||||
virtual void MakeFocus(bool focus);
|
||||
virtual void WindowActivated(bool active);
|
||||
|
||||
private:
|
||||
@@ -117,30 +102,20 @@ private:
|
||||
BRect fPathRect;
|
||||
BRect fLinkRect;
|
||||
BRect fDescRect;
|
||||
BRect fTitleRect;
|
||||
BRect fIconRect;
|
||||
BRect fSizeRect;
|
||||
BPoint fClickPoint;
|
||||
float fDivider;
|
||||
|
||||
BMenuField* fPreferredAppMenu;
|
||||
Model* fModel;
|
||||
Model* fIconModel;
|
||||
BBitmap* fIcon;
|
||||
bool fMouseDown;
|
||||
bool fDragging;
|
||||
bool fDoubleClick;
|
||||
track_state fTrackingState;
|
||||
bool fIsDropTarget;
|
||||
BTextView* fTitleEditView;
|
||||
PaneSwitch* fPermissionsSwitch;
|
||||
BWindow* fPathWindow;
|
||||
BWindow* fLinkWindow;
|
||||
BWindow* fDescWindow;
|
||||
color_which fCurrentLinkColorWhich;
|
||||
color_which fCurrentPathColorWhich;
|
||||
|
||||
typedef BView _inherited;
|
||||
typedef BGroupView _inherited;
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
@@ -150,7 +125,5 @@ const uint32 kPermissionsSelected = 'sepe';
|
||||
const uint32 kRecalculateSize = 'resz';
|
||||
const uint32 kSetLinkTarget = 'link';
|
||||
|
||||
const float kBorderWidth = 32.0f;
|
||||
|
||||
|
||||
#endif /* !GENERALINFOVIEW_H */
|
||||
|
||||
@@ -0,0 +1,724 @@
|
||||
/*
|
||||
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 "HeaderView.h"
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Application.h>
|
||||
#include <Catalog.h>
|
||||
#include <Locale.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <ScrollView.h>
|
||||
#include <Volume.h>
|
||||
#include <VolumeRoster.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "Commands.h"
|
||||
#include "FSUtils.h"
|
||||
#include "GeneralInfoView.h"
|
||||
#include "IconMenuItem.h"
|
||||
#include "Model.h"
|
||||
#include "NavMenu.h"
|
||||
#include "PoseView.h"
|
||||
#include "Tracker.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "InfoWindow"
|
||||
|
||||
|
||||
// Offsets taken from TAlertView::Draw in BAlert.cpp
|
||||
const float kIconHorizOffset = 18.0f;
|
||||
const float kIconVertOffset = 6.0f;
|
||||
const float kBorderWidth = 32.0f;
|
||||
|
||||
// Amount you have to move the mouse before a drag starts
|
||||
const float kDragSlop = 3.0f;
|
||||
|
||||
|
||||
HeaderView::HeaderView(Model* model)
|
||||
:
|
||||
BView("header", B_WILL_DRAW),
|
||||
fModel(model),
|
||||
fIconModel(model),
|
||||
fTitleEditView(NULL),
|
||||
fTrackingState(no_track),
|
||||
fMouseDown(false),
|
||||
fIsDropTarget(false),
|
||||
fDoubleClick(false),
|
||||
fDragging(false)
|
||||
{
|
||||
// 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);
|
||||
SetExplicitMinSize(BSize(B_SIZE_UNSET, B_LARGE_ICON + 2 * 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
HeaderView::~HeaderView()
|
||||
{
|
||||
if (fIconModel != fModel)
|
||||
delete fIconModel;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::ModelChanged(Model* model, BMessage* message)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::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;
|
||||
}
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::BeginEditingTitle()
|
||||
{
|
||||
if (fTitleEditView != NULL)
|
||||
return;
|
||||
|
||||
BFont font(be_plain_font);
|
||||
font.SetSize(font.Size() + 2);
|
||||
BRect textFrame(fTitleRect);
|
||||
textFrame.right = Bounds().Width() - 5;
|
||||
BRect textRect(textFrame);
|
||||
textRect.OffsetTo(0, 0);
|
||||
textRect.InsetBy(1, 1);
|
||||
|
||||
// Just make it some really large size, since we don't do any line
|
||||
// wrapping. The text filter will make sure to scroll the cursor
|
||||
// into position
|
||||
|
||||
textRect.right = 2000;
|
||||
fTitleEditView = new BTextView(textFrame, "text_editor",
|
||||
textRect, &font, 0, B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
fTitleEditView->SetText(fModel->Name());
|
||||
DisallowFilenameKeys(fTitleEditView);
|
||||
|
||||
// Reset the width of the text rect
|
||||
textRect = fTitleEditView->TextRect();
|
||||
textRect.right = fTitleEditView->LineWidth() + 20;
|
||||
fTitleEditView->SetTextRect(textRect);
|
||||
fTitleEditView->SetWordWrap(false);
|
||||
// Add filter for catching B_RETURN and B_ESCAPE key's
|
||||
fTitleEditView->AddFilter(
|
||||
new BMessageFilter(B_KEY_DOWN, HeaderView::TextViewFilter));
|
||||
|
||||
BScrollView* scrollView = new BScrollView("BorderView", fTitleEditView,
|
||||
0, 0, false, false, B_PLAIN_BORDER);
|
||||
AddChild(scrollView);
|
||||
fTitleEditView->SelectAll();
|
||||
fTitleEditView->MakeFocus();
|
||||
|
||||
Window()->UpdateIfNeeded();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::FinishEditingTitle(bool commit)
|
||||
{
|
||||
if (fTitleEditView == NULL)
|
||||
return;
|
||||
|
||||
bool reopen = false;
|
||||
|
||||
const char* text = fTitleEditView->Text();
|
||||
uint32 length = strlen(text);
|
||||
if (commit && strcmp(text, fModel->Name()) != 0
|
||||
&& length < B_FILE_NAME_LENGTH) {
|
||||
BEntry entry(fModel->EntryRef());
|
||||
BDirectory parent;
|
||||
if (entry.InitCheck() == B_OK
|
||||
&& entry.GetParent(&parent) == B_OK) {
|
||||
if (parent.Contains(text)) {
|
||||
BAlert* alert = new BAlert("",
|
||||
B_TRANSLATE("That name is already taken. "
|
||||
"Please type another one."),
|
||||
B_TRANSLATE("OK"),
|
||||
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go();
|
||||
reopen = true;
|
||||
} else {
|
||||
if (fModel->IsVolume()) {
|
||||
BVolume volume(fModel->NodeRef()->device);
|
||||
if (volume.InitCheck() == B_OK)
|
||||
volume.SetName(text);
|
||||
} else
|
||||
entry.Rename(text);
|
||||
|
||||
// Adjust the size of the text rect
|
||||
BFont currentFont(be_plain_font);
|
||||
currentFont.SetSize(currentFont.Size() + 2);
|
||||
fTitleRect.right = min_c(fTitleRect.left
|
||||
+ currentFont.StringWidth(fTitleEditView->Text()),
|
||||
Bounds().Width() - 5);
|
||||
}
|
||||
}
|
||||
} else if (length >= B_FILE_NAME_LENGTH) {
|
||||
BAlert* alert = new BAlert("",
|
||||
B_TRANSLATE("That name is too long. Please type another one."),
|
||||
B_TRANSLATE("OK"),
|
||||
0, 0, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go();
|
||||
reopen = true;
|
||||
}
|
||||
|
||||
// Remove view
|
||||
BView* scrollView = fTitleEditView->Parent();
|
||||
RemoveChild(scrollView);
|
||||
delete scrollView;
|
||||
fTitleEditView = NULL;
|
||||
|
||||
if (reopen)
|
||||
BeginEditingTitle();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::Draw(BRect)
|
||||
{
|
||||
// Set the low color for anti-aliasing
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// Clear the old contents
|
||||
SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
FillRect(Bounds());
|
||||
|
||||
rgb_color labelColor = ui_color(B_PANEL_TEXT_COLOR);
|
||||
|
||||
// Draw the icon, straddling the border
|
||||
SetDrawingMode(B_OP_OVER);
|
||||
IconCache::sIconCache->Draw(fIconModel, this, fIconRect.LeftTop(),
|
||||
kNormalIcon, B_LARGE_ICON, true);
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
|
||||
// Font information
|
||||
font_height fontMetrics;
|
||||
BFont currentFont;
|
||||
float lineHeight = 0;
|
||||
float lineBase = 0;
|
||||
|
||||
// Draw the main title if the user is not currently editing it
|
||||
if (fTitleEditView == NULL) {
|
||||
SetFont(be_bold_font);
|
||||
SetFontSize(be_bold_font->Size());
|
||||
GetFont(¤tFont);
|
||||
currentFont.GetHeight(&fontMetrics);
|
||||
lineHeight = CurrentFontHeight() + 5;
|
||||
lineBase = fTitleRect.bottom - fontMetrics.descent;
|
||||
SetHighColor(labelColor);
|
||||
MovePenTo(BPoint(fIconRect.right + 6, lineBase));
|
||||
|
||||
// Recalculate the rect width
|
||||
fTitleRect.right = min_c(
|
||||
fTitleRect.left + currentFont.StringWidth(fModel->Name()),
|
||||
Bounds().Width() - 5);
|
||||
// Check for possible need of truncation
|
||||
if (StringWidth(fModel->Name()) > fTitleRect.Width()) {
|
||||
BString nameString(fModel->Name());
|
||||
TruncateString(&nameString, B_TRUNCATE_END,
|
||||
fTitleRect.Width() - 2);
|
||||
DrawString(nameString.String());
|
||||
} else
|
||||
DrawString(fModel->Name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::MakeFocus(bool focus)
|
||||
{
|
||||
if (!focus && fTitleEditView != NULL)
|
||||
FinishEditingTitle(true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::WindowActivated(bool active)
|
||||
{
|
||||
if (active)
|
||||
return;
|
||||
|
||||
if (fTitleEditView != NULL)
|
||||
FinishEditingTitle(true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::MouseDown(BPoint where)
|
||||
{
|
||||
// Assume this isn't part of a double click
|
||||
fDoubleClick = false;
|
||||
|
||||
BEntry entry;
|
||||
fModel->GetEntry(&entry);
|
||||
|
||||
if (fTitleRect.Contains(where)) {
|
||||
if (!fModel->HasLocalizedName()
|
||||
&& ConfirmChangeIfWellKnownDirectory(&entry, kRename, true)) {
|
||||
BeginEditingTitle();
|
||||
}
|
||||
} else if (fTitleEditView) {
|
||||
FinishEditingTitle(true);
|
||||
} 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
|
||||
HeaderView::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;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fTrackingState) {
|
||||
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;
|
||||
|
||||
case no_track:
|
||||
// No mouse tracking, do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::MouseUp(BPoint where)
|
||||
{
|
||||
if ((fTrackingState == icon_track
|
||||
|| fTrackingState == open_only_track)
|
||||
&& fIconRect.Contains(where)) {
|
||||
// If it was a double click, then tell Tracker to open the item
|
||||
// The CurrentMessage() here does* not* have a "clicks" field,
|
||||
// which is why we are tracking the clicks with this temp var
|
||||
if (fDoubleClick) {
|
||||
// Double click, launch.
|
||||
BMessage message(B_REFS_RECEIVED);
|
||||
message.AddRef("refs", fModel->EntryRef());
|
||||
|
||||
// add a messenger to the launch message that will be used to
|
||||
// dispatch scripting calls from apps to the PoseView
|
||||
message.AddMessenger("TrackerViewToken", BMessenger(this));
|
||||
be_app->PostMessage(&message);
|
||||
fDoubleClick = false;
|
||||
}
|
||||
}
|
||||
|
||||
// End mouse tracking
|
||||
fMouseDown = false;
|
||||
fDragging = false;
|
||||
fTrackingState = no_track;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HeaderView::MessageReceived(BMessage* message)
|
||||
{
|
||||
if (message->WasDropped()
|
||||
&& message->what == B_SIMPLE_DATA
|
||||
&& message->ReturnAddress() != BMessenger(this)
|
||||
&& fIconRect.Contains(ConvertFromScreen(message->DropPoint()))
|
||||
&& BPoseView::CanHandleDragSelection(fModel, message,
|
||||
(modifiers() & B_CONTROL_KEY) != 0)) {
|
||||
BPoseView::HandleDropCommon(message, fModel, 0, this,
|
||||
message->DropPoint());
|
||||
Invalidate(fIconRect);
|
||||
return;
|
||||
}
|
||||
|
||||
BView::MessageReceived(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
HeaderView::BuildContextMenu(BMenu* parent)
|
||||
{
|
||||
if (parent == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// Add navigation menu if this is not a symlink
|
||||
// Symlink's to directories are OK however!
|
||||
BEntry entry(fModel->EntryRef());
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
Model model(&entry);
|
||||
bool navigate = false;
|
||||
if (model.InitCheck() == B_OK) {
|
||||
if (model.IsSymLink()) {
|
||||
// Check if it's to a directory
|
||||
if (entry.SetTo(model.EntryRef(), true) == B_OK) {
|
||||
navigate = entry.IsDirectory();
|
||||
entry.GetRef(&ref);
|
||||
}
|
||||
} else if (model.IsDirectory() || model.IsVolume())
|
||||
navigate = true;
|
||||
}
|
||||
ModelMenuItem* navigationItem = NULL;
|
||||
if (navigate) {
|
||||
navigationItem = new ModelMenuItem(new Model(model),
|
||||
new BNavMenu(model.Name(), B_REFS_RECEIVED, be_app, Window()));
|
||||
|
||||
// setup a navigation menu item which will dynamically load items
|
||||
// as menu items are traversed
|
||||
BNavMenu* navMenu = dynamic_cast<BNavMenu*>(navigationItem->Submenu());
|
||||
if (navMenu != NULL)
|
||||
navMenu->SetNavDir(&ref);
|
||||
|
||||
navigationItem->SetLabel(model.Name());
|
||||
navigationItem->SetEntry(&entry);
|
||||
|
||||
parent->AddItem(navigationItem, 0);
|
||||
parent->AddItem(new BSeparatorItem(), 1);
|
||||
|
||||
BMessage* message = new BMessage(B_REFS_RECEIVED);
|
||||
message->AddRef("refs", &ref);
|
||||
navigationItem->SetMessage(message);
|
||||
navigationItem->SetTarget(be_app);
|
||||
}
|
||||
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Open"),
|
||||
new BMessage(kOpenSelection), 'O'));
|
||||
|
||||
if (!model.IsDesktop() && !model.IsRoot() && !model.IsTrash()
|
||||
&& !fModel->HasLocalizedName()) {
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Edit name"),
|
||||
new BMessage(kEditItem), 'E'));
|
||||
parent->AddSeparatorItem();
|
||||
|
||||
if (fModel->IsVolume()) {
|
||||
BMenuItem* item = new BMenuItem(B_TRANSLATE("Unmount"),
|
||||
new BMessage(kUnmountVolume), 'U');
|
||||
parent->AddItem(item);
|
||||
// volume model, enable/disable the Unmount item
|
||||
BVolume boot;
|
||||
BVolumeRoster().GetBootVolume(&boot);
|
||||
BVolume volume;
|
||||
volume.SetTo(fModel->NodeRef()->device);
|
||||
if (volume == boot)
|
||||
item->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!model.IsRoot() && !model.IsVolume() && !model.IsTrash())
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Identify"),
|
||||
new BMessage(kIdentifyEntry)));
|
||||
|
||||
if (model.IsTrash())
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Empty Trash"),
|
||||
new BMessage(kEmptyTrash)));
|
||||
|
||||
BMenuItem* sizeItem = NULL;
|
||||
if (model.IsDirectory() && !model.IsVolume() && !model.IsRoot()) {
|
||||
parent->AddItem(sizeItem
|
||||
= new BMenuItem(B_TRANSLATE("Recalculate folder size"),
|
||||
new BMessage(kRecalculateSize)));
|
||||
}
|
||||
|
||||
if (model.IsSymLink()) {
|
||||
parent->AddItem(sizeItem
|
||||
= new BMenuItem(B_TRANSLATE("Set new link target"),
|
||||
new BMessage(kSetLinkTarget)));
|
||||
}
|
||||
|
||||
parent->AddItem(new BSeparatorItem());
|
||||
parent->AddItem(new BMenuItem(B_TRANSLATE("Permissions"),
|
||||
new BMessage(kPermissionsSelected), 'P'));
|
||||
|
||||
parent->SetFont(be_plain_font);
|
||||
parent->SetTargetForItems(this);
|
||||
|
||||
// Reset the nav menu to be_app
|
||||
if (navigate)
|
||||
navigationItem->SetTarget(be_app);
|
||||
if (sizeItem)
|
||||
sizeItem->SetTarget(Window());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
filter_result
|
||||
HeaderView::TextViewFilter(BMessage* message, BHandler**,
|
||||
BMessageFilter* filter)
|
||||
{
|
||||
uchar key;
|
||||
HeaderView* attribView = static_cast<HeaderView*>(
|
||||
static_cast<BWindow*>(filter->Looper())->FindView("header"));
|
||||
|
||||
// Adjust the size of the text rect
|
||||
BRect nuRect(attribView->TextView()->TextRect());
|
||||
nuRect.right = attribView->TextView()->LineWidth() + 20;
|
||||
attribView->TextView()->SetTextRect(nuRect);
|
||||
|
||||
// Make sure the cursor is in view
|
||||
attribView->TextView()->ScrollToSelection();
|
||||
if (message->FindInt8("byte", (int8*)&key) != B_OK)
|
||||
return B_DISPATCH_MESSAGE;
|
||||
|
||||
if (key == B_RETURN || key == B_ESCAPE) {
|
||||
attribView->FinishEditingTitle(key == B_RETURN);
|
||||
return B_SKIP_MESSAGE;
|
||||
}
|
||||
|
||||
return B_DISPATCH_MESSAGE;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
HeaderView::CurrentFontHeight()
|
||||
{
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
font_height fontHeight;
|
||||
font.GetHeight(&fontHeight);
|
||||
|
||||
return fontHeight.ascent + fontHeight.descent + fontHeight.leading + 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HEADERVIEW_H
|
||||
#define HEADERVIEW_H
|
||||
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Handler.h>
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <Rect.h>
|
||||
#include <TextView.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
class HeaderView: public BView {
|
||||
public:
|
||||
HeaderView(Model*);
|
||||
~HeaderView();
|
||||
|
||||
void ModelChanged(Model*, BMessage*);
|
||||
void ReLinkTargetModel(Model*);
|
||||
void BeginEditingTitle();
|
||||
void FinishEditingTitle(bool);
|
||||
virtual void Draw(BRect);
|
||||
virtual void MakeFocus(bool focus);
|
||||
virtual void WindowActivated(bool active);
|
||||
|
||||
BTextView* TextView() const { return fTitleEditView; }
|
||||
|
||||
protected:
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32, const BMessage* dragMessage);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
status_t BuildContextMenu(BMenu* parent);
|
||||
static filter_result TextViewFilter(BMessage*, BHandler**,
|
||||
BMessageFilter*);
|
||||
|
||||
float CurrentFontHeight();
|
||||
|
||||
private:
|
||||
// States for tracking the mouse
|
||||
enum track_state {
|
||||
no_track = 0,
|
||||
icon_track,
|
||||
open_only_track
|
||||
// This is for items that can be opened, but can't be
|
||||
// drag and dropped or renamed (Trash, Desktop Folder...)
|
||||
};
|
||||
|
||||
// Layouting
|
||||
BRect fTitleRect;
|
||||
BRect fIconRect;
|
||||
BPoint fClickPoint;
|
||||
|
||||
// Model data
|
||||
Model* fModel;
|
||||
Model* fIconModel;
|
||||
BBitmap* fIcon;
|
||||
BTextView* fTitleEditView;
|
||||
|
||||
// Mouse tracking
|
||||
track_state fTrackingState;
|
||||
bool fMouseDown;
|
||||
bool fIsDropTarget;
|
||||
bool fDoubleClick;
|
||||
bool fDragging;
|
||||
|
||||
typedef BView _inherited;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !HEADERVIEW_H */
|
||||
@@ -58,6 +58,7 @@ All rights reserved.
|
||||
#include <ScrollView.h>
|
||||
#include <StringFormat.h>
|
||||
#include <SymLink.h>
|
||||
#include <TabView.h>
|
||||
#include <TextView.h>
|
||||
#include <Volume.h>
|
||||
#include <VolumeRoster.h>
|
||||
@@ -96,7 +97,8 @@ BInfoWindow::BInfoWindow(Model* model, int32 group_index,
|
||||
:
|
||||
BWindow(BInfoWindow::InfoWindowRect(),
|
||||
"InfoWindow", B_TITLED_WINDOW,
|
||||
B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_CURRENT_WORKSPACE),
|
||||
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
|
||||
B_CURRENT_WORKSPACE),
|
||||
fModel(model),
|
||||
fStopCalc(false),
|
||||
fIndex(group_index),
|
||||
@@ -120,6 +122,31 @@ BInfoWindow::BInfoWindow(Model* model, int32 group_index,
|
||||
AddShortcut('U', 0, new BMessage(kUnmountVolume));
|
||||
AddShortcut('P', 0, new BMessage(kPermissionsSelected));
|
||||
|
||||
BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 0);
|
||||
SetLayout(layout);
|
||||
|
||||
BModelOpener modelOpener(TargetModel());
|
||||
if (TargetModel()->InitCheck() != B_OK)
|
||||
return;
|
||||
|
||||
AddChild(new HeaderView(TargetModel()));
|
||||
BTabView* tabView = new BTabView("tabs");
|
||||
tabView->SetBorder(B_NO_BORDER);
|
||||
AddChild(tabView);
|
||||
|
||||
fGeneralInfoView = new GeneralInfoView(TargetModel());
|
||||
tabView->AddTab(fGeneralInfoView);
|
||||
|
||||
BRect permissionsBounds(0,
|
||||
fGeneralInfoView->Bounds().bottom,
|
||||
fGeneralInfoView->Bounds().right,
|
||||
fGeneralInfoView->Bounds().bottom + 103);
|
||||
|
||||
fPermissionsView = new FilePermissionsView(
|
||||
permissionsBounds, fModel);
|
||||
tabView->AddTab(fPermissionsView);
|
||||
// This window accepts messages before being shown, so let's start the
|
||||
// looper immediately.
|
||||
Run();
|
||||
}
|
||||
|
||||
@@ -170,7 +197,6 @@ BInfoWindow::IsShowing(const node_ref* node) const
|
||||
void
|
||||
BInfoWindow::Show()
|
||||
{
|
||||
BModelOpener modelOpener(TargetModel());
|
||||
if (TargetModel()->InitCheck() != B_OK) {
|
||||
Close();
|
||||
return;
|
||||
@@ -178,22 +204,6 @@ BInfoWindow::Show()
|
||||
|
||||
AutoLock<BWindow> lock(this);
|
||||
|
||||
const BFont* font = be_plain_font;
|
||||
float width = font->StringWidth("This is a really long string which we"
|
||||
"will use to find the window width");
|
||||
|
||||
// window height depends on file type
|
||||
int lines = 9;
|
||||
if (fModel->IsExecutable())
|
||||
lines++;
|
||||
float height = font->Size() * (lines * 2 + 1);
|
||||
|
||||
ResizeTo(width, height);
|
||||
|
||||
BRect attrRect(Bounds());
|
||||
fGeneralInfoView = new GeneralInfoView(attrRect, TargetModel());
|
||||
AddChild(fGeneralInfoView);
|
||||
|
||||
// position window appropriately based on index
|
||||
BRect windRect(InfoWindowRect());
|
||||
if ((fIndex + 2) % 2 == 1) {
|
||||
@@ -261,7 +271,7 @@ BInfoWindow::MessageReceived(BMessage* message)
|
||||
BEntry entry(fModel->EntryRef());
|
||||
if (!fModel->HasLocalizedName()
|
||||
&& ConfirmChangeIfWellKnownDirectory(&entry, kRename)) {
|
||||
fGeneralInfoView->BeginEditingTitle();
|
||||
fHeaderView->BeginEditingTitle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -372,6 +382,7 @@ BInfoWindow::MessageReceived(BMessage* message)
|
||||
|
||||
// Tell the attribute view about this new model
|
||||
fGeneralInfoView->ReLinkTargetModel(TargetModel());
|
||||
fHeaderView->ReLinkTargetModel(TargetModel());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -429,6 +440,7 @@ BInfoWindow::MessageReceived(BMessage* message)
|
||||
// FilePermissionView::ModelChanged()
|
||||
// call, because it changes the model...
|
||||
// (bad style!)
|
||||
fHeaderView->ModelChanged(TargetModel(), message);
|
||||
|
||||
if (fPermissionsView != NULL)
|
||||
fPermissionsView->ModelChanged(TargetModel());
|
||||
@@ -453,28 +465,8 @@ BInfoWindow::MessageReceived(BMessage* message)
|
||||
|
||||
case kPermissionsSelected:
|
||||
{
|
||||
BRect permissionsBounds(kBorderWidth + 1,
|
||||
fGeneralInfoView->Bounds().bottom,
|
||||
fGeneralInfoView->Bounds().right,
|
||||
fGeneralInfoView->Bounds().bottom + 103);
|
||||
|
||||
if (fPermissionsView == NULL) {
|
||||
// Only true on first call.
|
||||
fPermissionsView = new FilePermissionsView(
|
||||
permissionsBounds, fModel);
|
||||
ResizeBy(0, permissionsBounds.Height());
|
||||
fGeneralInfoView->AddChild(fPermissionsView);
|
||||
fGeneralInfoView->SetPermissionsSwitchState(kPaneSwitchOpen);
|
||||
} else if (fPermissionsView->IsHidden()) {
|
||||
fPermissionsView->ModelChanged(fModel);
|
||||
fPermissionsView->Show();
|
||||
ResizeBy(0, permissionsBounds.Height());
|
||||
fGeneralInfoView->SetPermissionsSwitchState(kPaneSwitchOpen);
|
||||
} else {
|
||||
fPermissionsView->Hide();
|
||||
ResizeBy(0, -permissionsBounds.Height());
|
||||
fGeneralInfoView->SetPermissionsSwitchState(kPaneSwitchClosed);
|
||||
}
|
||||
BTabView* tabView = (BTabView*)FindView("tabs");
|
||||
tabView->Select(1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -594,10 +586,7 @@ BInfoWindow::CalcSize(void* castToWindow)
|
||||
void
|
||||
BInfoWindow::SetSizeString(const char* sizeString)
|
||||
{
|
||||
GeneralInfoView* view
|
||||
= dynamic_cast<GeneralInfoView*>(FindView("attr_view"));
|
||||
if (view != NULL)
|
||||
view->SetSizeString(sizeString);
|
||||
fGeneralInfoView->SetSizeString(sizeString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ All rights reserved.
|
||||
#include <MessageFilter.h>
|
||||
|
||||
#include "FilePermissionsView.h"
|
||||
#include "HeaderView.h"
|
||||
#include "LockingList.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
@@ -85,6 +86,7 @@ private:
|
||||
LockingList<BWindow>* fWindowList;
|
||||
FilePermissionsView* fPermissionsView;
|
||||
GeneralInfoView* fGeneralInfoView;
|
||||
HeaderView* fHeaderView;
|
||||
BFilePanel* fFilePanel;
|
||||
bool fFilePanelOpen;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user