From cf547998335ff6515000495485a7c8eeeb494858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 24 Feb 2004 03:39:23 +0000 Subject: [PATCH] Now maintains the "Paste" menu item - it is enabled/disabled when there is data available in the clipboard or not. "Copy" and "Select All" now work. All position updates are now handled by a separate looper class (UpdateLooper), and are actually applied at the editor. UpdateLooper will send a kMsgUpdateData to its target synchronously when necessary. Seeking a file now works nicely and very smooth. HeaderView::MessageReceived() and UpdateLooper::MessageReceived() only consider the most current update message for kMsgSliderUpdate resp. kMsgPositionUpdate. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6707 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/diskprobe/ProbeView.cpp | 153 +++++++++++++++++++++++++++++-- src/apps/diskprobe/ProbeView.h | 6 ++ 2 files changed, 153 insertions(+), 6 deletions(-) diff --git a/src/apps/diskprobe/ProbeView.cpp b/src/apps/diskprobe/ProbeView.cpp index 336b1aca43..3e5a367802 100644 --- a/src/apps/diskprobe/ProbeView.cpp +++ b/src/apps/diskprobe/ProbeView.cpp @@ -11,6 +11,9 @@ // for SetLimits() #include +#include +#include +#include #include #include #include @@ -123,6 +126,19 @@ class HeaderView : public BView, public BInvoker { }; +class UpdateLooper : public BLooper { + public: + UpdateLooper(const char *name, DataEditor &editor, BMessenger messenger); + virtual ~UpdateLooper(); + + virtual void MessageReceived(BMessage *message); + + private: + DataEditor &fEditor; + BMessenger fMessenger; +}; + + //---------------------- @@ -563,6 +579,16 @@ HeaderView::MessageReceived(BMessage *message) case kMsgSliderUpdate: { + // First, make sure we're only considering the most + // up-to-date message in the queue (which might not + // be this one). + // If there is another message of this type in the + // queue, we're just ignoring the current message. + + if (Looper()->MessageQueue()->FindMessage(kMsgSliderUpdate, 0) != NULL) + break; + + // if nothing has changed, we can ignore this message as well if (fPosition == fPositionSlider->Position()) break; @@ -629,6 +655,83 @@ HeaderView::MessageReceived(BMessage *message) // #pragma mark - +/** The purpose of this looper is to off-load the editor data + * loading from the main window looper. + * It will listen to the offset changes of the editor, let + * him update its data, and will then synchronously notify + * the target. + * That way, simple offset changes will not stop the main + * looper from operating. Therefore, all offset updates + * for the editor will go through this looper. + */ + +UpdateLooper::UpdateLooper(const char *name, DataEditor &editor, BMessenger target) + : BLooper(name), + fEditor(editor), + fMessenger(target) +{ + fEditor.StartWatching(this); +} + + +UpdateLooper::~UpdateLooper() +{ + fEditor.StopWatching(this); +} + + +void +UpdateLooper::MessageReceived(BMessage *message) +{ + switch (message->what) { + case kMsgPositionUpdate: + { + // First, make sure we're only considering the most + // up-to-date message in the queue (which might not + // be this one). + // If there is another message of this type in the + // queue, we're just ignoring the current message. + + if (Looper()->MessageQueue()->FindMessage(kMsgPositionUpdate, 0) != NULL) + break; + + off_t position; + if (message->FindInt64("position", &position) == B_OK) { + BAutolock locker(fEditor); + fEditor.SetViewOffset(position); + } + break; + } + + case kMsgDataEditorOffsetChange: + { + bool updated = false; + + if (fEditor.Lock()) { + fEditor.UpdateIfNeeded(&updated); + fEditor.Unlock(); + } + + if (updated) { + BMessage reply; + fMessenger.SendMessage(kMsgUpdateData, &reply); + // We are doing a synchronously transfer, to prevent + // that we're already locking the editor again when + // our target wants to get the editor data. + } + break; + } + + default: + BLooper::MessageReceived(message); + break; + } +} + + +// #pragma mark - + + ProbeView::ProbeView(BRect rect, entry_ref *ref, const char *attribute) : BView(rect, "probeView", B_FOLLOW_ALL, B_WILL_DRAW) { @@ -674,7 +777,14 @@ ProbeView::UpdateSizeLimits() void ProbeView::DetachedFromWindow() { + if (fUpdateLooper->Lock()) + fUpdateLooper->Quit(); + fUpdateLooper = NULL; + fEditor.StopWatching(this); + fDataView->StopWatching(fHeaderView, kDataViewCursorPosition); + fDataView->StopWatching(this, kDataViewSelection); + be_clipboard->StopWatching(this); } @@ -692,8 +802,13 @@ ProbeView::AddFileMenuItems(BMenu *menu, int32 index) void ProbeView::AttachedToWindow() { + fUpdateLooper = new UpdateLooper(fEditor.Ref().name, fEditor, BMessenger(fDataView)); + fUpdateLooper->Run(); + fEditor.StartWatching(this); fDataView->StartWatching(fHeaderView, kDataViewCursorPosition); + fDataView->StartWatching(this, kDataViewSelection); + be_clipboard->StartWatching(this); // Add menu to window @@ -719,9 +834,13 @@ ProbeView::AttachedToWindow() menu->AddItem(new BMenuItem("Undo", NULL, 'Z', B_COMMAND_KEY)); menu->AddItem(new BMenuItem("Redo", NULL, 'Z', B_COMMAND_KEY | B_SHIFT_KEY)); menu->AddSeparatorItem(); - menu->AddItem(new BMenuItem("Copy", NULL, 'C', B_COMMAND_KEY)); - menu->AddItem(new BMenuItem("Paste", NULL, 'V', B_COMMAND_KEY)); - menu->AddItem(new BMenuItem("Select All", NULL, 'A', B_COMMAND_KEY)); + menu->AddItem(item = new BMenuItem("Copy", new BMessage(B_COPY), 'C', B_COMMAND_KEY)); + item->SetTarget(fDataView); + menu->AddItem(fPasteMenuItem = new BMenuItem("Paste", new BMessage(B_PASTE), 'V', B_COMMAND_KEY)); + fPasteMenuItem->SetTarget(fDataView); + CheckClipboard(); + menu->AddItem(item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A', B_COMMAND_KEY)); + item->SetTarget(fDataView); menu->AddSeparatorItem(); menu->AddItem(new BMenuItem("Find" B_UTF8_ELLIPSIS, NULL, 'F', B_COMMAND_KEY)); menu->AddItem(new BMenuItem("Find Again", NULL, 'G', B_COMMAND_KEY)); @@ -799,7 +918,7 @@ ProbeView::AttachedToWindow() void ProbeView::AllAttached() { - fHeaderView->SetTarget(this); + fHeaderView->SetTarget(fUpdateLooper); } @@ -811,6 +930,28 @@ ProbeView::WindowActivated(bool active) } +void +ProbeView::CheckClipboard() +{ + if (!be_clipboard->Lock()) + return; + + bool hasData = false; + BMessage *clip; + if ((clip = be_clipboard->Data()) != NULL) { + const void *data; + ssize_t size; + if (clip->FindData(B_FILE_MIME_TYPE, B_MIME_TYPE, &data, &size) == B_OK + || clip->FindData("text/plain", B_MIME_TYPE, &data, &size) == B_OK) + hasData = true; + } + + be_clipboard->Unlock(); + + fPasteMenuItem->SetEnabled(hasData); +} + + void ProbeView::MessageReceived(BMessage *message) { @@ -826,8 +967,8 @@ ProbeView::MessageReceived(BMessage *message) break; } - case kMsgPositionUpdate: - // ToDo: update data + case B_CLIPBOARD_CHANGED: + CheckClipboard(); break; default: diff --git a/src/apps/diskprobe/ProbeView.h b/src/apps/diskprobe/ProbeView.h index 84a3ed8808..adb990dda8 100644 --- a/src/apps/diskprobe/ProbeView.h +++ b/src/apps/diskprobe/ProbeView.h @@ -14,9 +14,11 @@ class BScrollView; +class BMenuItem; class HeaderView; class DataView; +class UpdateLooper; class ProbeView : public BView { @@ -35,10 +37,14 @@ class ProbeView : public BView { void UpdateSizeLimits(); private: + void CheckClipboard(); + DataEditor fEditor; + UpdateLooper *fUpdateLooper; HeaderView *fHeaderView; DataView *fDataView; BScrollView *fScrollView; + BMenuItem *fPasteMenuItem; }; #endif /* PROBE_VIEW_H */