95da064570
1) We don't need to call FindPose() on every pose as we're freshly adding it, and a duplicate should never happen in this circumstance (the FindPose() is still there if Tracker is compiled in debug mode however. 2) Adjust the FSClipboard calls such that the locking is optional. This allows us to lock once per CreatePoses group rather than once per pose. Together these changes make for a significant performance improvement when it comes to populating a large folder. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29198 a95241bf-73f2-0310-859d-f6bbb57e9c96
855 lines
21 KiB
C++
855 lines
21 KiB
C++
/*
|
|
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 "FSClipboard.h"
|
|
#include <Clipboard.h>
|
|
#include <Alert.h>
|
|
#include <NodeMonitor.h>
|
|
#include "Commands.h"
|
|
#include "FSUtils.h"
|
|
#include "Tracker.h"
|
|
|
|
// prototypes
|
|
static void MakeNodeFromName(node_ref *node, char *name);
|
|
static inline void MakeRefName(char *refName, const node_ref *node);
|
|
static inline void MakeModeName(char *modeName, const node_ref *node);
|
|
static inline void MakeModeNameFromRefName(char *modeName, char *refName);
|
|
static inline bool CompareModeAndRefName(const char *modeName, const char *refName);
|
|
|
|
|
|
//these are from PoseView.cpp
|
|
extern const char *kNoCopyToTrashStr;
|
|
extern const char *kNoCopyToRootStr;
|
|
extern const char *kOkToMoveStr;
|
|
|
|
/*
|
|
static bool
|
|
FSClipboardCheckIntegrity()
|
|
{
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
static void
|
|
MakeNodeFromName(node_ref *node, char *name)
|
|
{
|
|
char *nodeString = strchr(name, '_');
|
|
if (nodeString != NULL) {
|
|
node->node = strtoll(nodeString + 1, (char **)NULL, 10);
|
|
node->device = atoi(name + 1);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void
|
|
MakeRefName(char *refName, const node_ref *node)
|
|
{
|
|
sprintf(refName, "r%ld_%Ld", node->device, node->node);
|
|
}
|
|
|
|
|
|
static inline void
|
|
MakeModeName(char *modeName, const node_ref *node)
|
|
{
|
|
sprintf(modeName, "m%ld_%Ld", node->device, node->node);
|
|
}
|
|
|
|
|
|
static inline void
|
|
MakeModeName(char *name)
|
|
{
|
|
name[0] = 'm';
|
|
}
|
|
|
|
|
|
static inline void
|
|
MakeModeNameFromRefName(char *modeName, char *refName)
|
|
{
|
|
strcpy(modeName, refName);
|
|
modeName[0] = 'm';
|
|
}
|
|
|
|
|
|
static inline bool
|
|
CompareModeAndRefName(const char *modeName, const char *refName)
|
|
{
|
|
return !strcmp(refName + 1, modeName + 1);
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
bool
|
|
FSClipboardHasRefs()
|
|
{
|
|
bool result = false;
|
|
|
|
if (be_clipboard->Lock()) {
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
#ifdef B_BEOS_VERSION_DANO
|
|
const
|
|
#endif
|
|
char *refName;
|
|
#ifdef B_BEOS_VERSION_DANO
|
|
const
|
|
#endif
|
|
char *modeName;
|
|
uint32 type;
|
|
int32 count;
|
|
if (clip->GetInfo(B_REF_TYPE, 0, &refName, &type, &count) == B_OK
|
|
&& clip->GetInfo(B_INT32_TYPE, 0, &modeName, &type, &count) == B_OK)
|
|
result = CompareModeAndRefName(modeName, refName);
|
|
}
|
|
be_clipboard->Unlock();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
FSClipboardStartWatch(BMessenger target)
|
|
{
|
|
if (dynamic_cast<TTracker *>(be_app) != NULL)
|
|
((TTracker *)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
|
|
else {
|
|
// this code is used by external apps using objects using FSClipboard functions
|
|
// i.e: applications using FilePanel
|
|
BMessenger messenger(kTrackerSignature);
|
|
if (messenger.IsValid()) {
|
|
BMessage message(kStartWatchClipboardRefs);
|
|
message.AddMessenger("target", target);
|
|
messenger.SendMessage(&message);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FSClipboardStopWatch(BMessenger target)
|
|
{
|
|
if (dynamic_cast<TTracker *>(be_app) != NULL)
|
|
((TTracker *)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
|
|
else {
|
|
// this code is used by external apps using objects using FSClipboard functions
|
|
// i.e: applications using FilePanel
|
|
BMessenger messenger(kTrackerSignature);
|
|
if (messenger.IsValid()) {
|
|
BMessage message(kStopWatchClipboardRefs);
|
|
message.AddMessenger("target", target);
|
|
messenger.SendMessage(&message);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FSClipboardClear()
|
|
{
|
|
if (!be_clipboard->Lock())
|
|
return;
|
|
|
|
be_clipboard->Clear();
|
|
be_clipboard->Commit();
|
|
be_clipboard->Unlock();
|
|
}
|
|
|
|
|
|
/** This function adds the given poses list to the clipboard, for both copy
|
|
* and cut. All poses in the list must have "directory" as parent.
|
|
* "moveMode" is either kMoveSelection or kCopySelection.
|
|
* It will check if the entries are already present, so that there can only
|
|
* be one reference to them in the clipboard.
|
|
*/
|
|
|
|
uint32
|
|
FSClipboardAddPoses(const node_ref *directory, PoseList *list, uint32 moveMode,
|
|
bool clearClipboard)
|
|
{
|
|
uint32 refsAdded = 0;
|
|
int32 listCount = list->CountItems();
|
|
|
|
if (listCount == 0 || !be_clipboard->Lock())
|
|
return 0;
|
|
|
|
// update message to be send to all listeners
|
|
BMessage updateMessage(kFSClipboardChanges);
|
|
updateMessage.AddInt32("device", directory->device);
|
|
updateMessage.AddInt64("directory", directory->node);
|
|
updateMessage.AddBool("clearClipboard", clearClipboard);
|
|
|
|
TClipboardNodeRef clipNode;
|
|
clipNode.moveMode = moveMode;
|
|
|
|
if (clearClipboard)
|
|
be_clipboard->Clear();
|
|
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
for (int32 index = 0; index < listCount; index++) {
|
|
char refName[64], modeName[64];
|
|
BPose *pose = (BPose *)list->ItemAt(index);
|
|
Model *model = pose->TargetModel();
|
|
const node_ref *node = model->NodeRef();
|
|
|
|
BEntry entry;
|
|
model->GetEntry(&entry);
|
|
if (model->IsVolume()
|
|
|| model->IsRoot()
|
|
|| FSIsTrashDir(&entry)
|
|
|| FSIsDeskDir(&entry))
|
|
continue;
|
|
|
|
MakeRefName(refName, node);
|
|
MakeModeNameFromRefName(modeName, refName);
|
|
|
|
if (clearClipboard) {
|
|
if (clip->AddInt32(modeName, (int32)moveMode) == B_OK)
|
|
if (clip->AddRef(refName, model->EntryRef()) == B_OK) {
|
|
pose->SetClipboardMode(moveMode);
|
|
|
|
clipNode.node = *node;
|
|
updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true, listCount);
|
|
|
|
refsAdded++;
|
|
} else
|
|
clip->RemoveName(modeName);
|
|
} else {
|
|
if (clip->ReplaceInt32(modeName, (int32)moveMode) == B_OK) {
|
|
// replace old mode if entry already exists in clipboard
|
|
if (clip->ReplaceRef(refName, model->EntryRef()) == B_OK) {
|
|
pose->SetClipboardMode(moveMode);
|
|
|
|
clipNode.node = *node;
|
|
updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true, listCount);
|
|
|
|
refsAdded++;
|
|
} else {
|
|
clip->RemoveName(modeName);
|
|
|
|
clipNode.node = *node;
|
|
clipNode.moveMode = kDelete; // note removing node
|
|
updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true, listCount);
|
|
clipNode.moveMode = moveMode; // set it back to current value
|
|
}
|
|
} else {
|
|
// add it if it doesn't exist
|
|
if (clip->AddRef(refName, model->EntryRef()) == B_OK
|
|
&& clip->AddInt32(modeName, (int32)moveMode) == B_OK) {
|
|
pose->SetClipboardMode(moveMode);
|
|
|
|
clipNode.node = *node;
|
|
updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true, listCount);
|
|
|
|
refsAdded++;
|
|
} else {
|
|
clip->RemoveName(modeName);
|
|
clip->RemoveName(refName);
|
|
// here notifying delete isn't needed as node didn't
|
|
// exist in clipboard
|
|
}
|
|
}
|
|
}
|
|
}
|
|
be_clipboard->Commit();
|
|
}
|
|
be_clipboard->Unlock();
|
|
|
|
BMessenger(kTrackerSignature).SendMessage(&updateMessage);
|
|
// Tracker will notify all listeners
|
|
|
|
return refsAdded;
|
|
}
|
|
|
|
|
|
uint32
|
|
FSClipboardRemovePoses(const node_ref *directory, PoseList *list)
|
|
{
|
|
if (!be_clipboard->Lock())
|
|
return 0;
|
|
|
|
// update message to be send to all listeners
|
|
BMessage updateMessage(kFSClipboardChanges);
|
|
updateMessage.AddInt32("device", directory->device);
|
|
updateMessage.AddInt64("directory", directory->node);
|
|
updateMessage.AddBool("clearClipboard", false);
|
|
|
|
TClipboardNodeRef clipNode;
|
|
clipNode.moveMode = kDelete;
|
|
|
|
uint32 refsRemoved = 0;
|
|
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
int32 listCount = list->CountItems();
|
|
|
|
for (int32 index = 0; index < listCount; index++) {
|
|
char refName[64], modeName[64];
|
|
BPose *pose = (BPose *)list->ItemAt(index);
|
|
|
|
clipNode.node = *pose->TargetModel()->NodeRef();
|
|
MakeRefName(refName, &clipNode.node);
|
|
MakeModeName(modeName);
|
|
|
|
if (clip->RemoveName(refName) == B_OK && clip->RemoveName(modeName)) {
|
|
updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true, listCount);
|
|
refsRemoved++;
|
|
}
|
|
}
|
|
be_clipboard->Commit();
|
|
}
|
|
be_clipboard->Unlock();
|
|
|
|
BMessenger(kTrackerSignature).SendMessage(&updateMessage);
|
|
// Tracker will notify all listeners
|
|
|
|
return refsRemoved;
|
|
}
|
|
|
|
|
|
/** Pastes entries from the clipboard to the target model's directory.
|
|
* Updates moveModes and notifies listeners if necessary.
|
|
*/
|
|
|
|
bool
|
|
FSClipboardPaste(Model *model, uint32 linksMode)
|
|
{
|
|
if (!FSClipboardHasRefs())
|
|
return false;
|
|
|
|
BMessenger tracker(kTrackerSignature);
|
|
|
|
node_ref *destNodeRef = (node_ref *)model->NodeRef();
|
|
|
|
// these will be passed to the asynchronous copy/move process
|
|
BObjectList<entry_ref> *moveList = new BObjectList<entry_ref>(0, true);
|
|
BObjectList<entry_ref> *copyList = new BObjectList<entry_ref>(0, true);
|
|
|
|
if ((be_clipboard->Lock())) {
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
char modeName[64];
|
|
uint32 moveMode = 0;
|
|
|
|
BMessage *updateMessage = NULL;
|
|
node_ref updateNodeRef;
|
|
updateNodeRef.device = -1;
|
|
|
|
char *refName;
|
|
type_code type;
|
|
int32 count;
|
|
for (int32 index = 0; clip->GetInfo(B_REF_TYPE, index,
|
|
#ifdef B_BEOS_VERSION_DANO
|
|
(const char **)
|
|
#endif
|
|
&refName, &type, &count) == B_OK; index++) {
|
|
entry_ref ref;
|
|
if (clip->FindRef(refName, &ref) != B_OK)
|
|
continue;
|
|
|
|
// If the entry_ref's directory has changed, send previous notification
|
|
// (if any), and start new one for the new directory
|
|
if (updateNodeRef.device != ref.device
|
|
|| updateNodeRef.node != ref.directory) {
|
|
if (updateMessage != NULL) {
|
|
tracker.SendMessage(updateMessage);
|
|
delete updateMessage;
|
|
}
|
|
|
|
updateNodeRef.device = ref.device;
|
|
updateNodeRef.node = ref.directory;
|
|
|
|
updateMessage = new BMessage(kFSClipboardChanges);
|
|
updateMessage->AddInt32("device", updateNodeRef.device);
|
|
updateMessage->AddInt64("directory", updateNodeRef.node);
|
|
}
|
|
|
|
// we need this data later on
|
|
MakeModeNameFromRefName(modeName, refName);
|
|
if (!linksMode && clip->FindInt32(modeName, (int32 *)&moveMode) != B_OK)
|
|
continue;
|
|
|
|
BEntry entry(&ref);
|
|
|
|
uint32 newMoveMode = 0;
|
|
bool sameDirectory = destNodeRef->device == ref.device && destNodeRef->node == ref.directory;
|
|
|
|
if (!entry.Exists()) {
|
|
// The entry doesn't exist anymore, so we'll remove
|
|
// that entry from the clipboard as well
|
|
clip->RemoveName(refName);
|
|
clip->RemoveName(modeName);
|
|
|
|
newMoveMode = kDelete;
|
|
} else {
|
|
// the entry does exist, so lets see what we will
|
|
// do with it
|
|
if (!sameDirectory) {
|
|
if (linksMode || moveMode == kMoveSelectionTo) {
|
|
// the linksMode uses the moveList as well
|
|
moveList->AddItem(new entry_ref(ref));
|
|
} else if (moveMode == kCopySelectionTo)
|
|
copyList->AddItem(new entry_ref(ref));
|
|
}
|
|
|
|
// if the entry should have been removed from its directory,
|
|
// we want to copy that entry next time, no matter if the
|
|
// items don't have to be moved at all (source == target)
|
|
if (moveMode == kMoveSelectionTo)
|
|
newMoveMode = kCopySelectionTo;
|
|
}
|
|
|
|
// add the change to the update message (if necessary)
|
|
if (newMoveMode) {
|
|
clip->ReplaceInt32(modeName, kCopySelectionTo);
|
|
|
|
TClipboardNodeRef clipNode;
|
|
MakeNodeFromName(&clipNode.node, modeName);
|
|
clipNode.moveMode = kDelete;
|
|
updateMessage->AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
|
|
sizeof(TClipboardNodeRef), true);
|
|
}
|
|
}
|
|
be_clipboard->Commit();
|
|
|
|
// send notification for the last directory
|
|
if (updateMessage != NULL) {
|
|
tracker.SendMessage(updateMessage);
|
|
delete updateMessage;
|
|
}
|
|
}
|
|
be_clipboard->Unlock();
|
|
}
|
|
|
|
bool okToMove = true;
|
|
|
|
// can't copy/paste to root('/') directory
|
|
if (model->IsRoot()) {
|
|
(new BAlert("", kNoCopyToRootStr, "Cancel", NULL, NULL,
|
|
B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
|
|
okToMove = false;
|
|
}
|
|
|
|
BEntry entry;
|
|
model->GetEntry(&entry);
|
|
|
|
// can't copy items into the trash
|
|
if (copyList->CountItems() > 0 && FSIsTrashDir(&entry)) {
|
|
(new BAlert("", kNoCopyToTrashStr, "Cancel", NULL, NULL,
|
|
B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
|
|
okToMove = false;
|
|
}
|
|
|
|
if (!okToMove) {
|
|
// there was some problem with our target, so we bail out here
|
|
delete moveList;
|
|
delete copyList;
|
|
return false;
|
|
}
|
|
|
|
// asynchronous calls take over ownership of the objects passed to it
|
|
if (moveList->CountItems() > 0)
|
|
FSMoveToFolder(moveList, new BEntry(entry), linksMode ? linksMode : kMoveSelectionTo);
|
|
else
|
|
delete moveList;
|
|
|
|
if (copyList->CountItems() > 0)
|
|
FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo);
|
|
else
|
|
delete copyList;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/** Seek node in clipboard, if found return it's moveMode
|
|
* else return 0
|
|
*/
|
|
|
|
uint32
|
|
FSClipboardFindNodeMode(Model *model, bool autoLock, bool updateRefIfNeeded)
|
|
{
|
|
int32 moveMode = 0;
|
|
if (autoLock) {
|
|
if (!be_clipboard->Lock())
|
|
return 0;
|
|
}
|
|
bool remove = false;
|
|
bool change = false;
|
|
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
const node_ref *node = model->NodeRef();
|
|
char modeName[64];
|
|
MakeModeName(modeName, node);
|
|
if ((clip->FindInt32(modeName, &moveMode) == B_OK)) {
|
|
const entry_ref *ref = model->EntryRef();
|
|
entry_ref clipref;
|
|
char refName[64];
|
|
MakeRefName(refName, node);
|
|
if ((clip->FindRef(refName, &clipref) == B_OK)) {
|
|
if (clipref != *ref) {
|
|
if (updateRefIfNeeded) {
|
|
clip->ReplaceRef(refName, ref);
|
|
change = true;
|
|
} else {
|
|
clip->RemoveName(refName);
|
|
clip->RemoveName(modeName);
|
|
change = true;
|
|
remove = true;
|
|
moveMode = 0;
|
|
}
|
|
}
|
|
} else {
|
|
clip->RemoveName(modeName);
|
|
change = true;
|
|
remove = true;
|
|
moveMode = 0;
|
|
}
|
|
}
|
|
}
|
|
if (change)
|
|
be_clipboard->Commit();
|
|
|
|
if (autoLock)
|
|
be_clipboard->Unlock();
|
|
|
|
if (remove)
|
|
FSClipboardRemove(model);
|
|
|
|
return (uint32)moveMode;
|
|
}
|
|
|
|
|
|
void
|
|
FSClipboardRemove(Model *model)
|
|
{
|
|
BMessenger messenger(kTrackerSignature);
|
|
if (messenger.IsValid()) {
|
|
BMessage *report = new BMessage(kFSClipboardChanges);
|
|
TClipboardNodeRef tcnode;
|
|
tcnode.node = *model->NodeRef();
|
|
tcnode.moveMode = kDelete;
|
|
const entry_ref *ref = model->EntryRef();
|
|
report->AddInt32("device", ref->device);
|
|
report->AddInt64("directory", ref->directory);
|
|
report->AddBool("clearClipboard", false);
|
|
report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode), true);
|
|
messenger.SendMessage(report);
|
|
delete report;
|
|
}
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
BClipboardRefsWatcher::BClipboardRefsWatcher()
|
|
: BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096),
|
|
fNotifyList(10, false)
|
|
{
|
|
watch_node(NULL, B_WATCH_MOUNT, this);
|
|
fRefsInClipboard = FSClipboardHasRefs();
|
|
be_clipboard->StartWatching(this);
|
|
}
|
|
|
|
|
|
BClipboardRefsWatcher::~BClipboardRefsWatcher()
|
|
{
|
|
stop_watching(this);
|
|
be_clipboard->StopWatching(this);
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::AddToNotifyList(BMessenger target)
|
|
{
|
|
if (Lock()) {
|
|
// add the messenger if it's not already in the list
|
|
// ToDo: why do we have to care about that?
|
|
BMessenger *messenger;
|
|
bool found = false;
|
|
|
|
for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) {
|
|
if (*messenger == target) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
fNotifyList.AddItem(new BMessenger(target));
|
|
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target)
|
|
{
|
|
if (Lock()) {
|
|
BMessenger *messenger;
|
|
|
|
for (int32 index = 0;(messenger = fNotifyList.ItemAt(index)) != NULL; index++) {
|
|
if (*messenger == target) {
|
|
delete fNotifyList.RemoveItemAt(index);
|
|
break;
|
|
}
|
|
}
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::AddNode(const node_ref *node)
|
|
{
|
|
TTracker::WatchNode(node, B_WATCH_NAME, this);
|
|
fRefsInClipboard = true;
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::RemoveNode(node_ref *node, bool removeFromClipboard)
|
|
{
|
|
watch_node(node, B_STOP_WATCHING, this);
|
|
|
|
if (!removeFromClipboard)
|
|
return;
|
|
|
|
if (be_clipboard->Lock()) {
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
char name[64];
|
|
MakeRefName(name, node);
|
|
clip->RemoveName(name);
|
|
MakeModeName(name);
|
|
clip->RemoveName(name);
|
|
|
|
be_clipboard->Commit();
|
|
}
|
|
be_clipboard->Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device)
|
|
{
|
|
if (!be_clipboard->Lock())
|
|
return;
|
|
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
char deviceName[6];
|
|
sprintf(deviceName, "r%ld_", device);
|
|
|
|
int32 index = 0;
|
|
char *refName;
|
|
type_code type;
|
|
int32 count;
|
|
while (clip->GetInfo(B_REF_TYPE, index,
|
|
#ifdef B_BEOS_VERSION_DANO
|
|
(const char **)
|
|
#endif
|
|
&refName, &type, &count) == B_OK) {
|
|
if (!strncmp(deviceName, refName, strlen(deviceName))) {
|
|
clip->RemoveName(refName);
|
|
MakeModeName(refName);
|
|
clip->RemoveName(refName);
|
|
|
|
node_ref node;
|
|
MakeNodeFromName(&node, refName);
|
|
watch_node(&node, B_STOP_WATCHING, this);
|
|
}
|
|
index++;
|
|
}
|
|
be_clipboard->Commit();
|
|
}
|
|
be_clipboard->Unlock();
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::UpdateNode(node_ref *node, entry_ref *ref)
|
|
{
|
|
if (!be_clipboard->Lock())
|
|
return;
|
|
|
|
BMessage *clip = be_clipboard->Data();
|
|
if (clip != NULL) {
|
|
char name[64];
|
|
MakeRefName(name, node);
|
|
if ((clip->ReplaceRef(name, ref)) != B_OK) {
|
|
clip->RemoveName(name);
|
|
MakeModeName(name);
|
|
clip->RemoveName(name);
|
|
|
|
RemoveNode(node);
|
|
}
|
|
be_clipboard->Commit();
|
|
}
|
|
be_clipboard->Unlock();
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::Clear()
|
|
{
|
|
stop_watching(this);
|
|
watch_node(NULL, B_WATCH_MOUNT, this);
|
|
|
|
BMessage message(kFSClipboardChanges);
|
|
message.AddBool("clearClipboard", true);
|
|
if (Lock()) {
|
|
int32 items = fNotifyList.CountItems();
|
|
for (int32 i = 0;i < items;i++) {
|
|
fNotifyList.ItemAt(i)->SendMessage(&message);
|
|
}
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
/*
|
|
void
|
|
BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard, const node_ref *node)
|
|
{
|
|
BMessage message(kFSClipboardChanges);
|
|
message.AddInt32("device", node->device);
|
|
message.AddInt64("directory", node->node);
|
|
message.AddBool("clearClipboard", clearClipboard);
|
|
|
|
if (Lock()) {
|
|
int32 items = fNotifyList.CountItems();
|
|
for (int32 i = 0;i < items;i++) {
|
|
fNotifyList.ItemAt(i)->SendMessage(&message);
|
|
}
|
|
Unlock();
|
|
}
|
|
}
|
|
*/
|
|
|
|
void
|
|
BClipboardRefsWatcher::UpdatePoseViews(BMessage *reportMessage)
|
|
{
|
|
if (Lock()) {
|
|
// check if it was cleared, if so clear watching
|
|
bool clearClipboard = false;
|
|
if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK
|
|
&& clearClipboard) {
|
|
stop_watching(this);
|
|
watch_node(NULL, B_WATCH_MOUNT, this);
|
|
}
|
|
|
|
// loop through reported node_ref's movemodes:
|
|
// move or copy: start watching node_ref
|
|
// remove: stop watching node_ref
|
|
int32 index = 0;
|
|
TClipboardNodeRef *tcnode = NULL;
|
|
ssize_t size;
|
|
while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index, (const void**)&tcnode, &size) == B_OK) {
|
|
if (tcnode->moveMode == kDelete) {
|
|
watch_node(&tcnode->node, B_STOP_WATCHING, this);
|
|
} else {
|
|
watch_node(&tcnode->node, B_STOP_WATCHING, this);
|
|
TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this);
|
|
fRefsInClipboard = true;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
// send report
|
|
int32 items = fNotifyList.CountItems();
|
|
for (int32 i = 0;i < items;i++) {
|
|
fNotifyList.ItemAt(i)->SendMessage(reportMessage);
|
|
}
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BClipboardRefsWatcher::MessageReceived(BMessage *message)
|
|
{
|
|
if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) {
|
|
if (!(fRefsInClipboard = FSClipboardHasRefs()))
|
|
Clear();
|
|
return;
|
|
} else if (message->what != B_NODE_MONITOR) {
|
|
_inherited::MessageReceived(message);
|
|
return;
|
|
}
|
|
|
|
switch (message->FindInt32("opcode")) {
|
|
case B_ENTRY_MOVED:
|
|
{
|
|
ino_t toDir;
|
|
ino_t fromDir;
|
|
node_ref node;
|
|
const char *name = NULL;
|
|
message->FindInt64("from directory", &fromDir);
|
|
message->FindInt64("to directory", &toDir);
|
|
message->FindInt64("node", &node.node);
|
|
message->FindInt32("device", &node.device);
|
|
message->FindString("name", &name);
|
|
entry_ref ref(node.device, toDir, name);
|
|
UpdateNode(&node, &ref);
|
|
break;
|
|
}
|
|
|
|
case B_DEVICE_UNMOUNTED:
|
|
{
|
|
dev_t device;
|
|
message->FindInt32("device", &device);
|
|
RemoveNodesByDevice(device);
|
|
break;
|
|
}
|
|
|
|
case B_ENTRY_REMOVED:
|
|
{
|
|
node_ref node;
|
|
message->FindInt64("node", &node.node);
|
|
message->FindInt32("device", &node.device);
|
|
RemoveNode(&node, true);
|
|
break;
|
|
}
|
|
}
|
|
}
|