850 lines
21 KiB
C++
850 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;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|
||
|
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 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 updateRefIfNeeded)
|
||
|
{
|
||
|
int32 moveMode = 0;
|
||
|
|
||
|
if (be_clipboard->Lock()) {
|
||
|
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();
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|