1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software..
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All rights reserved.
33*/
34
35#include "FSClipboard.h"
36#include <Clipboard.h>
37#include <Alert.h>
38#include <Catalog.h>
39#include <Locale.h>
40#include <NodeMonitor.h>
41#include "Commands.h"
42#include "FSUtils.h"
43#include "Tracker.h"
44
45
46// prototypes
47static void MakeNodeFromName(node_ref* node, char* name);
48static inline void MakeRefName(char* refName, const node_ref* node);
49static inline void MakeModeName(char* modeName, const node_ref* node);
50static inline void MakeModeNameFromRefName(char* modeName, char* refName);
51static inline bool CompareModeAndRefName(const char* modeName,
52	const char* refName);
53
54/*
55static bool
56FSClipboardCheckIntegrity()
57{
58	return true;
59}
60*/
61
62static void
63MakeNodeFromName(node_ref* node, char* name)
64{
65	char* nodeString = strchr(name, '_');
66	if (nodeString != NULL) {
67		node->node = strtoll(nodeString + 1, (char**)NULL, 10);
68		node->device = atoi(name + 1);
69	}
70}
71
72
73static inline void
74MakeRefName(char* refName, const node_ref* node)
75{
76	sprintf(refName, "r%" B_PRIdDEV "_%" B_PRIdINO, node->device, node->node);
77}
78
79
80static inline void
81MakeModeName(char* modeName, const node_ref* node)
82{
83	sprintf(modeName, "m%" B_PRIdDEV "_%" B_PRIdINO, node->device, node->node);
84}
85
86
87static inline void
88MakeModeName(char* name)
89{
90	name[0] = 'm';
91}
92
93
94static inline void
95MakeModeNameFromRefName(char* modeName, char* refName)
96{
97	strcpy(modeName, refName);
98	modeName[0] = 'm';
99}
100
101
102static inline bool
103CompareModeAndRefName(const char* modeName, const char* refName)
104{
105	return !strcmp(refName + 1, modeName + 1);
106}
107
108
109//	#pragma mark -
110
111
112#undef B_TRANSLATION_CONTEXT
113#define B_TRANSLATION_CONTEXT "FSClipBoard"
114
115bool
116FSClipboardHasRefs()
117{
118	bool result = false;
119
120	if (be_clipboard->Lock()) {
121		BMessage* clip = be_clipboard->Data();
122		if (clip != NULL) {
123#ifdef B_BEOS_VERSION_DANO
124			const
125#endif
126			char* refName;
127#ifdef B_BEOS_VERSION_DANO
128			const
129#endif
130			char* modeName;
131			uint32 type;
132			int32 count;
133			if (clip->GetInfo(B_REF_TYPE, 0, &refName, &type, &count) == B_OK
134				&& clip->GetInfo(B_INT32_TYPE, 0, &modeName, &type, &count)
135					== B_OK) {
136				result = CompareModeAndRefName(modeName, refName);
137			}
138		}
139		be_clipboard->Unlock();
140	}
141	return result;
142}
143
144
145void
146FSClipboardStartWatch(BMessenger target)
147{
148	if (dynamic_cast<TTracker*>(be_app) != NULL)
149		((TTracker*)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
150	else {
151		// this code is used by external apps using objects using FSClipboard
152		// functions, i.e. applications using FilePanel
153		BMessenger messenger(kTrackerSignature);
154		if (messenger.IsValid()) {
155			BMessage message(kStartWatchClipboardRefs);
156			message.AddMessenger("target", target);
157			messenger.SendMessage(&message);
158		}
159	}
160}
161
162
163void
164FSClipboardStopWatch(BMessenger target)
165{
166	if (dynamic_cast<TTracker*>(be_app) != NULL)
167		((TTracker*)be_app)->ClipboardRefsWatcher()->AddToNotifyList(target);
168	else {
169		// this code is used by external apps using objects using FSClipboard
170		// functions, i.e. applications using FilePanel
171		BMessenger messenger(kTrackerSignature);
172		if (messenger.IsValid()) {
173			BMessage message(kStopWatchClipboardRefs);
174			message.AddMessenger("target", target);
175			messenger.SendMessage(&message);
176		}
177	}
178}
179
180
181void
182FSClipboardClear()
183{
184	if (!be_clipboard->Lock())
185		return;
186
187	be_clipboard->Clear();
188	be_clipboard->Commit();
189	be_clipboard->Unlock();
190}
191
192
193/** This function adds the given poses list to the clipboard, for both copy
194 *	and cut. All poses in the list must have "directory" as parent.
195 *	"moveMode" is either kMoveSelection or kCopySelection.
196 *	It will check if the entries are already present, so that there can only
197 *	be one reference to them in the clipboard.
198 */
199
200uint32
201FSClipboardAddPoses(const node_ref* directory, PoseList* list,
202	uint32 moveMode, bool clearClipboard)
203{
204	uint32 refsAdded = 0;
205	int32 listCount = list->CountItems();
206
207	if (listCount == 0 || !be_clipboard->Lock())
208		return 0;
209
210	// update message to be send to all listeners
211	BMessage updateMessage(kFSClipboardChanges);
212	updateMessage.AddInt32("device", directory->device);
213	updateMessage.AddInt64("directory", directory->node);
214	updateMessage.AddBool("clearClipboard", clearClipboard);
215
216	TClipboardNodeRef clipNode;
217	clipNode.moveMode = moveMode;
218
219	if (clearClipboard)
220		be_clipboard->Clear();
221
222	BMessage* clip = be_clipboard->Data();
223	if (clip != NULL) {
224		for (int32 index = 0; index < listCount; index++) {
225			char refName[64], modeName[64];
226			BPose* pose = (BPose*)list->ItemAt(index);
227			Model* model = pose->TargetModel();
228			const node_ref* node = model->NodeRef();
229
230			BEntry entry;
231			model->GetEntry(&entry);
232			if (model->IsVolume()
233				|| model->IsRoot()
234				|| model->IsTrash()
235				|| model->IsDesktop())
236				continue;
237
238			MakeRefName(refName, node);
239			MakeModeNameFromRefName(modeName, refName);
240
241			if (clearClipboard) {
242				if (clip->AddInt32(modeName, (int32)moveMode) == B_OK) {
243					if (clip->AddRef(refName, model->EntryRef()) == B_OK) {
244						pose->SetClipboardMode(moveMode);
245
246						clipNode.node = *node;
247						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE,
248							&clipNode, sizeof(TClipboardNodeRef), true,
249							listCount);
250
251						refsAdded++;
252					} else
253						clip->RemoveName(modeName);
254				}
255			} else {
256				if (clip->ReplaceInt32(modeName, (int32)moveMode) == B_OK) {
257					// replace old mode if entry already exists in clipboard
258					if (clip->ReplaceRef(refName, model->EntryRef()) == B_OK) {
259						pose->SetClipboardMode(moveMode);
260
261						clipNode.node = *node;
262						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE,
263							&clipNode, sizeof(TClipboardNodeRef), true,
264							listCount);
265
266						refsAdded++;
267					} else {
268						clip->RemoveName(modeName);
269
270						clipNode.node = *node;
271						clipNode.moveMode = kDelete;	// note removing node
272						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE,
273							&clipNode, sizeof(TClipboardNodeRef), true,
274							listCount);
275						clipNode.moveMode = moveMode;
276							// set it back to current value
277					}
278				} else {
279					// add it if it doesn't exist
280					if (clip->AddRef(refName, model->EntryRef()) == B_OK
281						&& clip->AddInt32(modeName, (int32)moveMode) == B_OK) {
282						pose->SetClipboardMode(moveMode);
283
284						clipNode.node = *node;
285						updateMessage.AddData("tcnode", T_CLIPBOARD_NODE,
286							&clipNode, sizeof(TClipboardNodeRef), true,
287							listCount);
288
289						refsAdded++;
290					} else {
291						clip->RemoveName(modeName);
292						clip->RemoveName(refName);
293						// here notifying delete isn't needed as node didn't
294						// exist in clipboard
295					}
296				}
297			}
298		}
299		be_clipboard->Commit();
300	}
301	be_clipboard->Unlock();
302
303	BMessenger(kTrackerSignature).SendMessage(&updateMessage);
304		// Tracker will notify all listeners
305
306	return refsAdded;
307}
308
309
310uint32
311FSClipboardRemovePoses(const node_ref* directory, PoseList* list)
312{
313	if (!be_clipboard->Lock())
314		return 0;
315
316	// update message to be send to all listeners
317	BMessage updateMessage(kFSClipboardChanges);
318	updateMessage.AddInt32("device", directory->device);
319	updateMessage.AddInt64("directory", directory->node);
320	updateMessage.AddBool("clearClipboard", false);
321
322	TClipboardNodeRef clipNode;
323	clipNode.moveMode = kDelete;
324
325	uint32 refsRemoved = 0;
326
327	BMessage* clip = be_clipboard->Data();
328	if (clip != NULL) {
329		int32 listCount = list->CountItems();
330
331		for (int32 index = 0; index < listCount; index++) {
332			char refName[64], modeName[64];
333			BPose* pose = (BPose*)list->ItemAt(index);
334
335			clipNode.node = *pose->TargetModel()->NodeRef();
336			MakeRefName(refName, &clipNode.node);
337			MakeModeName(modeName);
338
339			if (clip->RemoveName(refName) == B_OK
340				&& clip->RemoveName(modeName)) {
341				updateMessage.AddData("tcnode", T_CLIPBOARD_NODE, &clipNode,
342					sizeof(TClipboardNodeRef), true, listCount);
343				refsRemoved++;
344			}
345		}
346		be_clipboard->Commit();
347	}
348	be_clipboard->Unlock();
349
350	BMessenger(kTrackerSignature).SendMessage(&updateMessage);
351		// Tracker will notify all listeners
352
353	return refsRemoved;
354}
355
356
357/** Pastes entries from the clipboard to the target model's directory.
358 *	Updates moveModes and notifies listeners if necessary.
359 */
360bool
361FSClipboardPaste(Model* model, uint32 linksMode)
362{
363	if (!FSClipboardHasRefs())
364		return false;
365
366	BMessenger tracker(kTrackerSignature);
367
368	node_ref* destNodeRef = (node_ref*)model->NodeRef();
369
370	// these will be passed to the asynchronous copy/move process
371	BObjectList<entry_ref>* moveList = new BObjectList<entry_ref>(0, true);
372	BObjectList<entry_ref>* copyList = new BObjectList<entry_ref>(0, true);
373
374	if ((be_clipboard->Lock())) {
375		BMessage* clip = be_clipboard->Data();
376		if (clip != NULL) {
377			char modeName[64];
378			uint32 moveMode = 0;
379
380			BMessage* updateMessage = NULL;
381			node_ref updateNodeRef;
382			updateNodeRef.device = -1;
383
384			char* refName;
385			type_code type;
386			int32 count;
387			for (int32 index = 0; clip->GetInfo(B_REF_TYPE, index,
388#ifdef B_BEOS_VERSION_DANO
389				(const char**)
390#endif
391				&refName, &type, &count) == B_OK; index++) {
392				entry_ref ref;
393				if (clip->FindRef(refName, &ref) != B_OK)
394					continue;
395
396				// If the entry_ref's directory has changed, send previous notification
397				// (if any), and start new one for the new directory
398				if (updateNodeRef.device != ref.device
399					|| updateNodeRef.node != ref.directory) {
400					if (updateMessage != NULL) {
401						tracker.SendMessage(updateMessage);
402						delete updateMessage;
403					}
404
405					updateNodeRef.device = ref.device;
406					updateNodeRef.node = ref.directory;
407
408					updateMessage = new BMessage(kFSClipboardChanges);
409					updateMessage->AddInt32("device", updateNodeRef.device);
410					updateMessage->AddInt64("directory", updateNodeRef.node);
411				}
412
413				// we need this data later on
414				MakeModeNameFromRefName(modeName, refName);
415				if (!linksMode && clip->FindInt32(modeName, (int32*)&moveMode)
416					!= B_OK) {
417					continue;
418				}
419
420				BEntry entry(&ref);
421
422				uint32 newMoveMode = 0;
423				bool sameDirectory = destNodeRef->device == ref.device
424					&& destNodeRef->node == ref.directory;
425
426				if (!entry.Exists()) {
427					// The entry doesn't exist anymore, so we'll remove
428					// that entry from the clipboard as well
429					clip->RemoveName(refName);
430					clip->RemoveName(modeName);
431
432					newMoveMode = kDelete;
433				} else {
434					// the entry does exist, so lets see what we will
435					// do with it
436					if (!sameDirectory) {
437						if (linksMode || moveMode == kMoveSelectionTo) {
438							// the linksMode uses the moveList as well
439							moveList->AddItem(new entry_ref(ref));
440						} else if (moveMode == kCopySelectionTo)
441							copyList->AddItem(new entry_ref(ref));
442					}
443
444					// if the entry should have been removed from its
445					// directory, we want to copy that entry next time, no
446					// matter if the items don't have to be moved at all
447					// (source == target)
448					if (moveMode == kMoveSelectionTo)
449						newMoveMode = kCopySelectionTo;
450				}
451
452				// add the change to the update message (if necessary)
453				if (newMoveMode) {
454					clip->ReplaceInt32(modeName, kCopySelectionTo);
455
456					TClipboardNodeRef clipNode;
457					MakeNodeFromName(&clipNode.node, modeName);
458					clipNode.moveMode = kDelete;
459					updateMessage->AddData("tcnode", T_CLIPBOARD_NODE,
460						&clipNode, sizeof(TClipboardNodeRef), true);
461				}
462			}
463			be_clipboard->Commit();
464
465			// send notification for the last directory
466			if (updateMessage != NULL) {
467				tracker.SendMessage(updateMessage);
468				delete updateMessage;
469			}
470		}
471		be_clipboard->Unlock();
472	}
473
474	bool okToMove = true;
475
476	// can't copy/paste to root('/') directory
477	if (model->IsRoot()) {
478		BAlert* alert = new BAlert("",
479			B_TRANSLATE("You must drop items on one of the disk icons "
480			"in the \"Disks\" window."), B_TRANSLATE("Cancel"), NULL, NULL,
481			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
482		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
483		alert->Go();
484		okToMove = false;
485	}
486
487	BEntry entry;
488	model->GetEntry(&entry);
489
490	// can't copy items into the trash
491	if (copyList->CountItems() > 0 && model->IsTrash()) {
492		BAlert* alert = new BAlert("",
493			B_TRANSLATE("Sorry, you can't copy items to the Trash."),
494			B_TRANSLATE("Cancel"), NULL, NULL, B_WIDTH_AS_USUAL,
495			B_WARNING_ALERT);
496		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
497		alert->Go();
498		okToMove = false;
499	}
500
501	if (!okToMove) {
502		// there was some problem with our target, so we bail out here
503		delete moveList;
504		delete copyList;
505		return false;
506	}
507
508	// asynchronous calls take over ownership of the objects passed to it
509	if (moveList->CountItems() > 0) {
510		FSMoveToFolder(moveList, new BEntry(entry),
511			linksMode ? linksMode : kMoveSelectionTo);
512	} else
513		delete moveList;
514
515	if (copyList->CountItems() > 0)
516		FSMoveToFolder(copyList, new BEntry(entry), kCopySelectionTo);
517	else
518		delete copyList;
519
520	return true;
521}
522
523
524// Seek node in clipboard, if found return it's moveMode
525// else return 0
526uint32
527FSClipboardFindNodeMode(Model* model, bool autoLock, bool updateRefIfNeeded)
528{
529	int32 moveMode = 0;
530	if (autoLock) {
531		if (!be_clipboard->Lock())
532			return 0;
533	}
534	bool remove = false;
535	bool change = false;
536
537	BMessage* clip = be_clipboard->Data();
538	if (clip != NULL) {
539		const node_ref* node = model->NodeRef();
540		char modeName[64];
541		MakeModeName(modeName, node);
542		if ((clip->FindInt32(modeName, &moveMode) == B_OK)) {
543			const entry_ref* ref = model->EntryRef();
544			entry_ref clipref;
545			char refName[64];
546			MakeRefName(refName, node);
547			if ((clip->FindRef(refName, &clipref) == B_OK)) {
548				if (clipref != *ref) {
549					if (updateRefIfNeeded) {
550						clip->ReplaceRef(refName, ref);
551						change = true;
552					} else {
553						clip->RemoveName(refName);
554						clip->RemoveName(modeName);
555						change = true;
556						remove = true;
557						moveMode = 0;
558					}
559				}
560			} else {
561				clip->RemoveName(modeName);
562				change = true;
563				remove = true;
564				moveMode = 0;
565			}
566		}
567	}
568	if (change)
569		be_clipboard->Commit();
570
571	if (autoLock)
572		be_clipboard->Unlock();
573
574	if (remove)
575		FSClipboardRemove(model);
576
577	return (uint32)moveMode;
578}
579
580
581void
582FSClipboardRemove(Model* model)
583{
584	BMessenger messenger(kTrackerSignature);
585	if (messenger.IsValid()) {
586		BMessage* report = new BMessage(kFSClipboardChanges);
587		TClipboardNodeRef tcnode;
588		tcnode.node = *model->NodeRef();
589		tcnode.moveMode = kDelete;
590		const entry_ref* ref = model->EntryRef();
591		report->AddInt32("device", ref->device);
592		report->AddInt64("directory", ref->directory);
593		report->AddBool("clearClipboard", false);
594		report->AddData("tcnode", T_CLIPBOARD_NODE, &tcnode, sizeof(tcnode),
595			true);
596		messenger.SendMessage(report);
597		delete report;
598	}
599}
600
601
602//	#pragma mark -
603
604
605BClipboardRefsWatcher::BClipboardRefsWatcher()
606	:	BLooper("ClipboardRefsWatcher", B_LOW_PRIORITY, 4096),
607	fNotifyList(10, false)
608{
609	watch_node(NULL, B_WATCH_MOUNT, this);
610	fRefsInClipboard = FSClipboardHasRefs();
611	be_clipboard->StartWatching(this);
612}
613
614
615BClipboardRefsWatcher::~BClipboardRefsWatcher()
616{
617	stop_watching(this);
618	be_clipboard->StopWatching(this);
619}
620
621
622void
623BClipboardRefsWatcher::AddToNotifyList(BMessenger target)
624{
625	if (Lock()) {
626		// add the messenger if it's not already in the list
627		// ToDo: why do we have to care about that?
628		BMessenger* messenger;
629		bool found = false;
630
631		for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL;
632				index++) {
633			if (*messenger == target) {
634				found = true;
635				break;
636			}
637		}
638		if (!found)
639			fNotifyList.AddItem(new BMessenger(target));
640
641		Unlock();
642	}
643}
644
645
646void
647BClipboardRefsWatcher::RemoveFromNotifyList(BMessenger target)
648{
649	if (Lock()) {
650		BMessenger* messenger;
651
652		for (int32 index = 0; (messenger = fNotifyList.ItemAt(index)) != NULL;
653				index++) {
654			if (*messenger == target) {
655				delete fNotifyList.RemoveItemAt(index);
656				break;
657			}
658		}
659		Unlock();
660	}
661}
662
663
664void
665BClipboardRefsWatcher::AddNode(const node_ref* node)
666{
667	TTracker::WatchNode(node, B_WATCH_NAME, this);
668	fRefsInClipboard = true;
669}
670
671
672void
673BClipboardRefsWatcher::RemoveNode(node_ref* node, bool removeFromClipboard)
674{
675	watch_node(node, B_STOP_WATCHING, this);
676
677	if (!removeFromClipboard)
678		return;
679
680	if (be_clipboard->Lock()) {
681		BMessage* clip = be_clipboard->Data();
682		if (clip != NULL) {
683			char name[64];
684			MakeRefName(name, node);
685			clip->RemoveName(name);
686			MakeModeName(name);
687			clip->RemoveName(name);
688
689			be_clipboard->Commit();
690		}
691		be_clipboard->Unlock();
692	}
693}
694
695
696void
697BClipboardRefsWatcher::RemoveNodesByDevice(dev_t device)
698{
699	if (!be_clipboard->Lock())
700		return;
701
702	BMessage* clip = be_clipboard->Data();
703	if (clip != NULL) {
704		char deviceName[6];
705		sprintf(deviceName, "r%" B_PRIdDEV "_", device);
706
707		int32 index = 0;
708		char* refName;
709		type_code type;
710		int32 count;
711		while (clip->GetInfo(B_REF_TYPE, index,
712#ifdef B_BEOS_VERSION_DANO
713			(const char**)
714#endif
715			&refName, &type, &count) == B_OK) {
716			if (!strncmp(deviceName, refName, strlen(deviceName))) {
717				clip->RemoveName(refName);
718				MakeModeName(refName);
719				clip->RemoveName(refName);
720
721				node_ref node;
722				MakeNodeFromName(&node, refName);
723				watch_node(&node, B_STOP_WATCHING, this);
724			}
725			index++;
726		}
727		be_clipboard->Commit();
728	}
729	be_clipboard->Unlock();
730}
731
732
733void
734BClipboardRefsWatcher::UpdateNode(node_ref* node, entry_ref* ref)
735{
736	if (!be_clipboard->Lock())
737		return;
738
739	BMessage* clip = be_clipboard->Data();
740	if (clip != NULL) {
741		char name[64];
742		MakeRefName(name, node);
743		if ((clip->ReplaceRef(name, ref)) != B_OK) {
744			clip->RemoveName(name);
745			MakeModeName(name);
746			clip->RemoveName(name);
747
748			RemoveNode(node);
749		}
750		be_clipboard->Commit();
751	}
752	be_clipboard->Unlock();
753}
754
755
756void
757BClipboardRefsWatcher::Clear()
758{
759	stop_watching(this);
760	watch_node(NULL, B_WATCH_MOUNT, this);
761
762	BMessage message(kFSClipboardChanges);
763	message.AddBool("clearClipboard", true);
764	if (Lock()) {
765		int32 items = fNotifyList.CountItems();
766		for (int32 i = 0;i < items;i++) {
767			fNotifyList.ItemAt(i)->SendMessage(&message);
768		}
769		Unlock();
770	}
771}
772
773
774//void
775//BClipboardRefsWatcher::UpdatePoseViews(bool clearClipboard,
776//	const node_ref* node)
777//{
778//	BMessage message(kFSClipboardChanges);
779//	message.AddInt32("device", node->device);
780//	message.AddInt64("directory", node->node);
781//	message.AddBool("clearClipboard", clearClipboard);
782//
783//	if (Lock()) {
784//		int32 items = fNotifyList.CountItems();
785//		for (int32 i = 0;i < items;i++) {
786//			fNotifyList.ItemAt(i)->SendMessage(&message);
787//		}
788//		Unlock();
789//	}
790//}
791
792
793void
794BClipboardRefsWatcher::UpdatePoseViews(BMessage* reportMessage)
795{
796	if (Lock()) {
797		// check if it was cleared, if so clear watching
798		bool clearClipboard = false;
799		if (reportMessage->FindBool("clearClipboard", &clearClipboard) == B_OK
800			&& clearClipboard) {
801			stop_watching(this);
802			watch_node(NULL, B_WATCH_MOUNT, this);
803		}
804
805		// loop through reported node_ref's movemodes:
806		// move or copy: start watching node_ref
807		// remove: stop watching node_ref
808		int32 index = 0;
809		TClipboardNodeRef* tcnode = NULL;
810		ssize_t size;
811		while (reportMessage->FindData("tcnode", T_CLIPBOARD_NODE, index,
812				(const void**)&tcnode, &size) == B_OK) {
813			if (tcnode->moveMode == kDelete) {
814				watch_node(&tcnode->node, B_STOP_WATCHING, this);
815			} else {
816				watch_node(&tcnode->node, B_STOP_WATCHING, this);
817				TTracker::WatchNode(&tcnode->node, B_WATCH_NAME, this);
818				fRefsInClipboard = true;
819			}
820			index++;
821		}
822
823		// send report
824		int32 items = fNotifyList.CountItems();
825		for (int32 i = 0;i < items;i++) {
826			fNotifyList.ItemAt(i)->SendMessage(reportMessage);
827		}
828		Unlock();
829	}
830}
831
832
833void
834BClipboardRefsWatcher::MessageReceived(BMessage* message)
835{
836	if (message->what == B_CLIPBOARD_CHANGED && fRefsInClipboard) {
837		if (!(fRefsInClipboard = FSClipboardHasRefs()))
838			Clear();
839		return;
840	} else if (message->what != B_NODE_MONITOR) {
841		_inherited::MessageReceived(message);
842		return;
843	}
844
845	switch (message->FindInt32("opcode")) {
846		case B_ENTRY_MOVED:
847		{
848			ino_t toDir;
849			ino_t fromDir;
850			node_ref node;
851			const char* name = NULL;
852			message->FindInt64("from directory", &fromDir);
853			message->FindInt64("to directory", &toDir);
854			message->FindInt64("node", &node.node);
855			message->FindInt32("device", &node.device);
856			message->FindString("name", &name);
857			entry_ref ref(node.device, toDir, name);
858			UpdateNode(&node, &ref);
859			break;
860		}
861
862		case B_DEVICE_UNMOUNTED:
863		{
864			dev_t device;
865			message->FindInt32("device", &device);
866			RemoveNodesByDevice(device);
867			break;
868		}
869
870		case B_ENTRY_REMOVED:
871		{
872			node_ref node;
873			message->FindInt64("node", &node.node);
874			message->FindInt32("device", &node.device);
875			RemoveNode(&node, true);
876			break;
877		}
878	}
879}
880