hrev44507 adds 2 changesets to branch 'master' old head: 6adbfc19ef9d2f4b5f59977ffe2e5f5b74e49302 new head: 741e52463a4e1df441230669a38f1bb8832f9674 ---------------------------------------------------------------------------- e0e641c: Tracker: Style fixes, should have no functional change 741e524: Tracker: Double-click management changes Make the "second click of a double-click" detection waiting time async. In other words (hopefully clearer), when the TextWidget gets a click, it register itself, recording the time, and it will get the editing order later as a callback from PoseView when the delay without any further click expires. Fixes #8818 and maybe others. [ Philippe Saint-Pierre <stpere@xxxxxxxxx> ] ---------------------------------------------------------------------------- 6 files changed, 124 insertions(+), 80 deletions(-) src/kits/tracker/PoseList.cpp | 13 +++-- src/kits/tracker/PoseList.h | 2 +- src/kits/tracker/PoseView.cpp | 68 +++++++++++++++---------- src/kits/tracker/PoseView.h | 14 ++++-- src/kits/tracker/TextWidget.cpp | 93 +++++++++++++++++++---------------- src/kits/tracker/TextWidget.h | 14 ++++++ ############################################################################ Commit: e0e641c07817564664d01a01db95ce2af5f4c63d URL: http://cgit.haiku-os.org/haiku/commit/?id=e0e641c Author: Philippe Saint-Pierre <stpere@xxxxxxxxx> Date: Thu Aug 9 20:36:10 2012 UTC Tracker: Style fixes, should have no functional change ---------------------------------------------------------------------------- diff --git a/src/kits/tracker/PoseList.cpp b/src/kits/tracker/PoseList.cpp index 4e5d8fd..d90e7b0 100644 --- a/src/kits/tracker/PoseList.cpp +++ b/src/kits/tracker/PoseList.cpp @@ -114,8 +114,8 @@ PoseList::DeepFindPose(const node_ref* node, int32* resultingIndex) const } -PoseList * -PoseList::FindAllPoses(const node_ref *node) const +PoseList* +PoseList::FindAllPoses(const node_ref* node) const { int32 count = CountItems(); PoseList *result = new PoseList(5, false); @@ -131,16 +131,15 @@ PoseList::FindAllPoses(const node_ref *node) const continue; model = model->LinkTo(); - if (model && *model->NodeRef() == *node) { + if (model != NULL && *model->NodeRef() == *node) { result->AddItem(pose); continue; } - if (!model) { - model = new Model(pose->TargetModel()->EntryRef(), true); - if (*model->NodeRef() == *node) + if (model == NULL) { + Model model(pose->TargetModel()->EntryRef(), true); + if (*model.NodeRef() == *node) result->AddItem(pose); - delete model; } } return result; diff --git a/src/kits/tracker/PoseList.h b/src/kits/tracker/PoseList.h index 801a08f..072e130 100644 --- a/src/kits/tracker/PoseList.h +++ b/src/kits/tracker/PoseList.h @@ -66,7 +66,7 @@ public: BPose* DeepFindPose(const node_ref* node, int32* index = NULL) const; // same as FindPose, node can be a target of the actual // pose if the pose is a symlink - PoseList *FindAllPoses(const node_ref *node) const; + PoseList* FindAllPoses(const node_ref* node) const; }; // iteration glue, add permutations as needed diff --git a/src/kits/tracker/PoseView.cpp b/src/kits/tracker/PoseView.cpp index 70ae3a9..f28390f 100644 --- a/src/kits/tracker/PoseView.cpp +++ b/src/kits/tracker/PoseView.cpp @@ -2655,7 +2655,7 @@ BPoseView::RemoveColumn(BColumn* columnToRemove, bool runAlert) // the column we removed might just be the one that was used to filter int32 count = fFilteredPoseList->CountItems(); for (int32 i = count - 1; i >= 0; i--) { - BPose *pose = fFilteredPoseList->ItemAt(i); + BPose* pose = fFilteredPoseList->ItemAt(i); if (!FilterPose(pose)) RemoveFilteredPose(pose, i); } @@ -4953,15 +4953,15 @@ BPoseView::MoveSelectionTo(BPoint dropPt, BPoint clickPt, inline void -UpdateWasBrokenSymlinkBinder(BPose *pose, Model *model, int32 index, - BPoseView *poseView, BObjectList<Model> *fBrokenLinks) +UpdateWasBrokenSymlinkBinder(BPose* pose, Model* model, int32 index, + BPoseView* poseView, BObjectList<Model>* fBrokenLinks) { if (!model->IsSymLink()) return; BPoint loc(0, index * poseView->ListElemHeight()); pose->UpdateWasBrokenSymlink(loc, poseView); - if (model->LinkTo()) + if (model->LinkTo() != NULL) fBrokenLinks->RemoveItem(model); } @@ -4973,7 +4973,7 @@ BPoseView::TryUpdatingBrokenLinks() if (!lock) return; - BObjectList<Model> *brokenLinksCopy = new BObjectList<Model>(*fBrokenLinks); + BObjectList<Model>* brokenLinksCopy = new BObjectList<Model>(*fBrokenLinks); // try fixing broken symlinks, and detecting broken ones. EachPoseAndModel(fPoseList, &UpdateWasBrokenSymlinkBinder, this, @@ -4995,7 +4995,7 @@ BPoseView::PoseHandleDeviceUnmounted(BPose* pose, Model* model, int32 index, if (model->NodeRef()->device == device) poseView->DeletePose(model->NodeRef()); else if (model->IsSymLink() - && model->LinkTo() + && model->LinkTo() != NULL && model->LinkTo()->NodeRef()->device == device) poseView->DeleteSymLinkPoseTarget(model->LinkTo()->NodeRef(), pose, index); } @@ -5150,7 +5150,7 @@ BPoseView::FSNotification(const BMessage* message) createPose = false; } - const char *name; + const char* name; if (message->FindString("name", &name) != B_OK) break; #if DEBUG @@ -5165,7 +5165,7 @@ BPoseView::FSNotification(const BMessage* message) // exist yet. We are looking if the just created folder // is 'some_folder' and watch it, expecting the creation of // 'another_folder' later and then report the link as fixed. - Model *model = new Model(&dirNode, &itemNode, name); + Model* model = new Model(&dirNode, &itemNode, name); if (model->IsDirectory()) { BString createdPath(BPath(model->EntryRef()).Path()); BDirectory currentDir(TargetModel()->EntryRef()); @@ -5302,8 +5302,8 @@ BPoseView::FSNotification(const BMessage* message) bool BPoseView::CreateSymlinkPoseTarget(Model* symlink) { - Model *newResolvedModel = NULL; - Model *result = symlink->LinkTo(); + Model* newResolvedModel = NULL; + Model* result = symlink->LinkTo(); if (!result) { BEntry entry(symlink->EntryRef(), true); if (entry.InitCheck() == B_OK) { @@ -5429,7 +5429,7 @@ BPoseView::EntryMoved(const BMessage* message) // rename or move of entry in this directory (or query) int32 index; - BPose *pose = fPoseList->FindPose(&itemNode, &index); + BPose* pose = fPoseList->FindPose(&itemNode, &index); int32 poseListIndex = index; bool visible = true; if (fFiltering) @@ -5489,7 +5489,7 @@ BPoseView::EntryMoved(const BMessage* message) void -BPoseView::WatchParentOf(const entry_ref *ref) +BPoseView::WatchParentOf(const entry_ref* ref) { BPath currentDir(ref); currentDir.GetParent(¤tDir); @@ -5525,7 +5525,7 @@ BPoseView::StopWatchingParentsOf(const entry_ref* ref) if (path.InitCheck() != B_OK) return; - BObjectList<Model> *brokenLinksCopy = new BObjectList<Model>(*fBrokenLinks); + BObjectList<Model>* brokenLinksCopy = new BObjectList<Model>(*fBrokenLinks); int32 count = brokenLinksCopy->CountItems(); while (path.GetParent(&path) == B_OK) { @@ -5589,11 +5589,11 @@ BPoseView::AttributeChanged(const BMessage* message) int32 index; attr_info info; - PoseList *posesFound = fPoseList->FindAllPoses(&itemNode); + PoseList* posesFound = fPoseList->FindAllPoses(&itemNode); int32 posesCount = posesFound->CountItems(); for (int i = 0; i < posesCount; i++) { - BPose *pose = posesFound->ItemAt(i); - Model *model = pose->TargetModel(); + BPose* pose = posesFound->ItemAt(i); + Model* model = pose->TargetModel(); if (model->IsSymLink() && *model->NodeRef() != itemNode) // change happened on symlink's target model = model->ResolveIfLink(); @@ -5797,7 +5797,7 @@ BPoseView::DuplicateSelection(BPoint* dropStart, BPoint* dropEnd) // create entry_ref list from selection if (!fSelectionList->IsEmpty()) { - BObjectList<entry_ref> *srcList = new BObjectList<entry_ref>( + BObjectList<entry_ref>* srcList = new BObjectList<entry_ref>( fSelectionList->CountItems(), true); CopySelectionListToBListAsEntryRefs(fSelectionList, srcList); @@ -5823,13 +5823,13 @@ BPoseView::SelectPoseAtLocation(BPoint point) void -BPoseView::MoveListToTrash(BObjectList<entry_ref> *list, bool selectNext, +BPoseView::MoveListToTrash(BObjectList<entry_ref>* list, bool selectNext, bool deleteDirectly) { if (!list->CountItems()) return; - BObjectList<FunctionObject> *taskList = + BObjectList<FunctionObject>* taskList = new BObjectList<FunctionObject>(2, true); // new owning list of tasks @@ -7221,7 +7221,7 @@ BPoseView::WasDoubleClick(const BPose* pose, BPoint point) static void -AddPoseRefToMessage(BPose *, Model* model, BMessage* message) +AddPoseRefToMessage(BPose*, Model* model, BMessage* message) { // Make sure that every file added to the message has its // MIME type set. @@ -7743,7 +7743,7 @@ BPoseView::DeletePose(const node_ref* itemNode, BPose* pose, int32 index) if (pose->TargetModel()->IsSymLink()) { fBrokenLinks->RemoveItem(pose->TargetModel()); StopWatchingParentsOf(pose->TargetModel()->EntryRef()); - Model *target = pose->TargetModel()->LinkTo(); + Model* target = pose->TargetModel()->LinkTo(); if (target) watch_node(target->NodeRef(), B_STOP_WATCHING, this); } diff --git a/src/kits/tracker/PoseView.h b/src/kits/tracker/PoseView.h index 88b30a0..f366412 100644 --- a/src/kits/tracker/PoseView.h +++ b/src/kits/tracker/PoseView.h @@ -674,8 +674,8 @@ class BPoseView : public BView { void Delete(const entry_ref&ref, bool selectNext, bool askUser); void RestoreItemsFromTrash(BObjectList<entry_ref>*, bool selectNext); - void WatchParentOf(const entry_ref *); - void StopWatchingParentsOf(const entry_ref *); + void WatchParentOf(const entry_ref*); + void StopWatchingParentsOf(const entry_ref*); private: void DrawOpenAnimation(BRect); @@ -698,9 +698,9 @@ class BPoseView : public BView { // used for mime string based icon highliting during a drag BObjectList<Model>* fZombieList; PendingNodeMonitorCache pendingNodeMonitorCache; - BObjectList<BColumn> *fColumnList; - BObjectList<BString> *fMimeTypeList; - BObjectList<Model> *fBrokenLinks; + BObjectList<BColumn>* fColumnList; + BObjectList<BString>* fMimeTypeList; + BObjectList<Model>* fBrokenLinks; bool fMimeTypeListIsDirty; BViewState* fViewState; bool fStateNeedsSaving; ############################################################################ Revision: hrev44507 Commit: 741e52463a4e1df441230669a38f1bb8832f9674 URL: http://cgit.haiku-os.org/haiku/commit/?id=741e524 Author: Philippe Saint-Pierre <stpere@xxxxxxxxx> Date: Fri Aug 10 03:08:46 2012 UTC Ticket: https://dev.haiku-os.org/ticket/8818 Tracker: Double-click management changes Make the "second click of a double-click" detection waiting time async. In other words (hopefully clearer), when the TextWidget gets a click, it register itself, recording the time, and it will get the editing order later as a callback from PoseView when the delay without any further click expires. Fixes #8818 and maybe others. ---------------------------------------------------------------------------- diff --git a/src/kits/tracker/PoseView.cpp b/src/kits/tracker/PoseView.cpp index f28390f..7137888 100644 --- a/src/kits/tracker/PoseView.cpp +++ b/src/kits/tracker/PoseView.cpp @@ -265,7 +265,8 @@ BPoseView::BPoseView(Model* model, BRect bounds, uint32 viewMode, fLastFilterStringLength(0), fLastKeyTime(0), fLastDeskbarFrameCheckTime(LONGLONG_MIN), - fDeskbarFrame(0, 0, -1, -1) + fDeskbarFrame(0, 0, -1, -1), + fTextWidgetToCheck(NULL) { fViewState->SetViewMode(viewMode); fShowSelectionWhenInactive @@ -914,6 +915,11 @@ BPoseView::Pulse() fLastLeftTop = LeftTop(); } } + + // do we have a TextWidget waiting for expiracy of its double-click + // check? + if (fTextWidgetToCheck != NULL) + fTextWidgetToCheck->CheckExpiration(); } @@ -1399,10 +1405,10 @@ BPoseView::AddPosesTask(void* castToParams) } view->ReadPoseInfo(model, - &(posesResult->fPoseInfos[modelChunkIndex])); + &posesResult->fPoseInfos[modelChunkIndex]); if (!PoseVisible(model, - &(posesResult->fPoseInfos[modelChunkIndex]))) { + &posesResult->fPoseInfos[modelChunkIndex])) { modelChunkIndex--; continue; } @@ -7123,6 +7129,13 @@ BPoseView::MouseDown(BPoint where) void +BPoseView::SetTextWidgetToCheck(BTextWidget* widget) +{ + fTextWidgetToCheck = widget; +} + + +void BPoseView::MouseUp(BPoint where) { if (fSelectionRectInfo.isDragging) @@ -7131,7 +7144,8 @@ BPoseView::MouseUp(BPoint where) int32 index; BPose* pose = FindPose(where, &index); uint32 lastButtons = Window()->CurrentMessage()->FindInt32("last_buttons"); - if (pose != NULL && fAllowPoseEditing && !fTrackRightMouseUp) + if (pose != NULL && fLastClickedPose != NULL && fAllowPoseEditing + && !fTrackRightMouseUp) pose->MouseUp(BPoint(0, index * fListElemHeight), this, where, index); @@ -7210,6 +7224,10 @@ BPoseView::WasDoubleClick(const BPose* pose, BPoint point) fLastClickPt.Set(LONG_MAX, LONG_MAX); fLastClickedPose = NULL; fLastClickTime = 0; + if (fTextWidgetToCheck != NULL) { + fTextWidgetToCheck->CancelWait(); + fTextWidgetToCheck = NULL; + } return true; } diff --git a/src/kits/tracker/PoseView.h b/src/kits/tracker/PoseView.h index f366412..09f21e8 100644 --- a/src/kits/tracker/PoseView.h +++ b/src/kits/tracker/PoseView.h @@ -425,6 +425,8 @@ class BPoseView : public BView { virtual void AdaptToVolumeChange(BMessage*); virtual void AdaptToDesktopIntegrationChange(BMessage*); + void SetTextWidgetToCheck(BTextWidget*); + protected: // view setup virtual void SetUpDefaultColumnsIfNeeded(); @@ -778,6 +780,8 @@ class BPoseView : public BView { static OffscreenBitmap* sOffscreen; + BTextWidget* fTextWidgetToCheck; + typedef BView _inherited; }; diff --git a/src/kits/tracker/TextWidget.cpp b/src/kits/tracker/TextWidget.cpp index e1e00dc..46333ad 100644 --- a/src/kits/tracker/TextWidget.cpp +++ b/src/kits/tracker/TextWidget.cpp @@ -70,7 +70,8 @@ BTextWidget::BTextWidget(Model* model, BColumn* column, BPoseView* view) fEditable(column->Editable()), fVisible(true), fActive(false), - fSymLink(model->IsSymLink()) + fSymLink(model->IsSymLink()), + fLastClickedTime(0) { } @@ -218,57 +219,65 @@ BTextWidget::CalcClickRect(BPoint poseLoc, const BColumn* column, void +BTextWidget::CheckExpiration() +{ + if (IsEditable() && fParams.pose->IsSelected() && fLastClickedTime) { + bigtime_t doubleClickSpeed; + get_click_speed(&doubleClickSpeed); + + bigtime_t delta = system_time() - fLastClickedTime; + + if (delta > doubleClickSpeed) { + // at least 'doubleClickSpeed' microseconds ellapsed and no click + // was registered since. + fLastClickedTime = 0; + fParams.poseView->SetTextWidgetToCheck(NULL); + StartEdit(fParams.bounds, fParams.poseView, fParams.pose); + } + } else { + fLastClickedTime = 0; + fParams.poseView->SetTextWidgetToCheck(NULL); + } +} + + +void +BTextWidget::CancelWait() +{ + fLastClickedTime = 0; +} + + +void BTextWidget::MouseUp(BRect bounds, BPoseView* view, BPose* pose, BPoint) { - // Start editing without delay if the pose was selected recently and this - // click is not the second click of a doubleclick. - // If the pose has been selected a long time ago, check again - // for a double click (inducing a delay). + // Register the time of that click. The PoseView, through its Pulse() + // will allow us to StartEdit() if no other click have been registered since + // then. // TODO: re-enable modifiers, one should be enough - + view->SetTextWidgetToCheck(NULL); if (IsEditable() && pose->IsSelected()) { - bigtime_t delta = system_time() - pose->SelectionTime(); bigtime_t doubleClickSpeed; get_click_speed(&doubleClickSpeed); - bigtime_t oldClickSpeed = 2 * doubleClickSpeed; - // freshly selected and not a double click - if (delta > doubleClickSpeed && delta < oldClickSpeed) { - StartEdit(bounds, view, pose); + if (fLastClickedTime == 0) { + fLastClickedTime = system_time(); + if (fLastClickedTime - doubleClickSpeed < pose->SelectionTime()) + fLastClickedTime = 0; + } else + fLastClickedTime = 0; + + if (fLastClickedTime == 0) return; - } - // TODO: reimplement asynchronous - // selected a longer time ago, redo a double click detection - if (delta > oldClickSpeed) { - // check for double click - bigtime_t doubleClickTime = system_time() + doubleClickSpeed; - while (system_time() < doubleClickTime) { - // loop for double-click time and watch the mouse and keyboard - - BPoint point; - uint32 buttons; - view->GetMouse(&point, &buttons, false); - - // double click - if (buttons) - return; - - // mouse moved too far - if (!bounds.Contains(point)) - return; - - //if (modifiers() & (B_SHIFT_KEY | B_COMMAND_KEY - // | B_CONTROL_KEY | B_MENU_KEY)) - // // watch the keyboard (ignoring standard locking keys) - // break; - - snooze(10000); - } - StartEdit(bounds, view, pose); - } - } + view->SetTextWidgetToCheck(this); + + fParams.pose = pose; + fParams.bounds = bounds; + fParams.poseView = view; + } else + fLastClickedTime = 0; } diff --git a/src/kits/tracker/TextWidget.h b/src/kits/tracker/TextWidget.h index 0c4f011..1c3e9df 100644 --- a/src/kits/tracker/TextWidget.h +++ b/src/kits/tracker/TextWidget.h @@ -44,6 +44,14 @@ class BPose; class BPoseView; class BColumn; + +struct MouseUpParams { + BPose* pose; + BRect bounds; + BPoseView* poseView; +}; + + class BTextWidget { public: BTextWidget(Model*, BColumn*, BPoseView*); @@ -93,6 +101,9 @@ public: float PreferredWidth(const BPoseView*) const; int Compare(const BTextWidget&, BPoseView*) const; // used for sorting in PoseViews + + void CheckExpiration(); + void CancelWait(); private: BRect CalcRectCommon(BPoint poseLoc, const BColumn*, const BPoseView*, @@ -107,6 +118,9 @@ private: bool fVisible : 1; bool fActive : 1; bool fSymLink : 1; + + bigtime_t fLastClickedTime; + struct MouseUpParams fParams; };