[PATCH] Actions on svn revision items

Mirek Jezbera <[email protected]> Fri, 21 Dec 2012 13:43:50 +0100
Newsgroups gmane.comp.version-control.subversion.rapidsvn.devel
Message-ID <20121221124350.GE20812@titan>
------=_Part_17887_1057412048.1356103752063
Content-Type: multipart/mixed; 
	boundary="----=_Part_17888_1497111811.1356103752063"
Content-Disposition: inline

------=_Part_17888_1497111811.1356103752063
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,
I am sending patches, that allows in Log dialog diff, view & annotate each
affected file (log is not implemented, yet). So you can do Log on directory
(either for working copy or for repository) and examine changes.
Feel free to review changes and send your opinions.

--=20
Jezz
mail:   [email protected]
jabber: [email protected]

------=_Part_17888_1497111811.1356103752063
Content-Type: text/x-diff; charset=us-ascii; 
	name=01_multiselect_log_dialog.diff
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=01_multiselect_log_dialog.diff

Index: librapidsvn/src/log_dlg.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/log_dlg.cpp=09(revision 2)
+++ librapidsvn/src/log_dlg.cpp=09(revision 4)
@@ -22,6 +22,9 @@
  * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
  */
=20
+// stl
+#include <algorithm>
+
 // wx windows
 #include "wx/wx.h"
 #include "wx/valgen.h"
@@ -185,7 +188,8 @@
   if (1 !=3D count)
   {
     m_textLog->Clear();
-    m_listFiles->DeleteAllItems();
+    ReduceSelectionToOnlyTwoItems();
+    FillAffectedFiles();
   }
   else
   {
@@ -198,20 +202,20 @@
     m_textLog->SetValue(message);
     m_listFiles->SetValue(entry.changedPaths);
   }
+  CheckControls();
 }
=20
-
 void
 LogDlg::OnRevSelected(wxListEvent & WXUNUSED(event))
 {
-  CheckControls();
+  UpdateSelection();
 }
=20
=20
 void
 LogDlg::OnRevDeselected(wxListEvent & WXUNUSED(event))
 {
-  CheckControls();
+  UpdateSelection();
 }
=20
=20
@@ -225,8 +229,6 @@
   bool twoRevs =3D 2 =3D=3D count;
   bool oneRev =3D 1 =3D=3D count;
=20
-  UpdateSelection();
-
   m_buttonGet->Enable(oneRev && (!isUrl));
   m_buttonView->Enable(oneRev);
=20
@@ -241,6 +243,123 @@
   m_buttonAnnotate->Enable(oneRev);
 }
=20
+void
+LogDlg::ReduceSelectionToOnlyTwoItems()
+{
+  if (m_listRevisions->GetSelectedItemCount() <=3D 2)
+  {
+    return;
+  }
+
+  long previousSelectedItemIndex =3D m_listRevisions->GetNextSelected(m_li=
stRevisions->GetFirstSelected()),
+       selectedItemIndex =3D m_listRevisions->GetNextSelected(previousSele=
ctedItemIndex);
+  bool focusedWasSelected =3D false;
+
+  while (selectedItemIndex !=3D -1)
+  {
+    if (previousSelectedItemIndex =3D=3D m_listRevisions->GetFocusedItem()=
)
+    {
+      focusedWasSelected =3D true;
+    }
+    else
+    {
+      m_listRevisions->Select(previousSelectedItemIndex, false);
+    }
+    previousSelectedItemIndex =3D selectedItemIndex;
+    selectedItemIndex =3D m_listRevisions->GetNextSelected(previousSelecte=
dItemIndex);
+  }
+
+  if (focusedWasSelected)
+  {
+    m_listRevisions->Select(previousSelectedItemIndex, false);
+  }
+}
+
+void
+LogDlg::FillAffectedFiles()
+{
+  m_listFiles->DeleteAllItems();
+
+  long firstSelectedItemIndex =3D m_listRevisions->GetFirstSelected();
+  if (firstSelectedItemIndex =3D=3D -1)
+  {
+    return;
+  }
+
+  const svn::LogEntry & entry =3D (*m->entries)[firstSelectedItemIndex];
+  std::list<svn::LogChangePathEntry> changedPaths =3D entry.changedPaths;
+
+  if (m_listRevisions->GetSelectedItemCount() > 1)
+  {
+    std::set<std::string> affectedPaths =3D GetIntersectionOfAffectedPaths=
();
+    changedPaths =3D FilterAffectedPaths(changedPaths, affectedPaths);
+  }
+
+  m_listFiles->SetValue(changedPaths);
+}
+
+std::set<std::string>
+LogDlg::GetIntersectionOfAffectedPaths()
+{
+  long firstSelectedItemIndex =3D m_listRevisions->GetFirstSelected();
+  std::set<std::string> affectedPaths =3D GetAffectedPathsForItem(firstSel=
ectedItemIndex);
+  long nextSelectedItemIndex =3D m_listRevisions->GetNextSelected(firstSel=
ectedItemIndex);
+
+  while (nextSelectedItemIndex !=3D -1)
+  {
+    std::set<std::string> nextAffectedPaths =3D GetAffectedPathsForItem(ne=
xtSelectedItemIndex);
+    std::vector<std::string> intersection(affectedPaths.size());
+
+    set_intersection(affectedPaths.begin(), affectedPaths.end(),
+        nextAffectedPaths.begin(), nextAffectedPaths.end(),
+        intersection.begin());
+    affectedPaths =3D std::set<std::string>(intersection.begin(), intersec=
tion.end());
+
+    nextSelectedItemIndex =3D m_listRevisions->GetNextSelected(nextSelecte=
dItemIndex);
+  }
+
+  return affectedPaths;
+}
+
+std::list<svn::LogChangePathEntry>
+LogDlg::FilterAffectedPaths(std::list<svn::LogChangePathEntry> const & cha=
ngedPaths, std::set<std::string> const & filter)
+{
+  std::list<svn::LogChangePathEntry> result;
+
+  for (std::list<svn::LogChangePathEntry>::const_iterator it =3D changedPa=
ths.begin();
+      it !=3D changedPaths.end();
+      ++it)
+  {
+    if (filter.find(it->path) !=3D filter.end())
+    {
+      result.push_back(*it);
+    }
+  }
+
+  return result;
+}
+
+std::set<std::string>
+LogDlg::GetAffectedPathsForItem(long itemIndex)
+{
+  if (itemIndex < 0)
+  {
+    return std::set<std::string>();
+  }
+
+  std::set<std::string> result;
+  const svn::LogEntry & entry =3D (*m->entries)[itemIndex];
+
+  for (std::list<svn::LogChangePathEntry>::const_iterator it =3D entry.cha=
ngedPaths.begin();
+      it !=3D entry.changedPaths.end();
+      ++it)
+  {
+    result.insert(it->path);
+  }
+
+  return result;
+}
+
 /* -----------------------------------------------------------------
  * local variables:
  * eval: (load-file "../rapidsvn-dev.el")
Index: librapidsvn/include/log_rev_list.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_rev_list.hpp=09(revision 2)
+++ librapidsvn/include/log_rev_list.hpp=09(revision 4)
@@ -34,14 +34,14 @@
 #include "utils.hpp"
=20
=20
-class LogRevList : public wxListCtrl
+class LogRevList : public wxListView
 {
 public:
   LogRevList(wxWindow * parent, wxWindowID id, const wxPoint& pos =3D wxDe=
faultPosition,=20
              const wxSize& size =3D wxDefaultSize, long style =3D wxLC_REP=
ORT,=20
              const wxValidator& validator =3D wxDefaultValidator,=20
              const wxString& name =3D wxT("LogRevList"))
-    : wxListCtrl(parent, id, pos, size, style, validator, name)
+    : wxListView(parent, id, pos, size, style, validator, name)
   {
     InsertColumn(0, _("Revision"));
     InsertColumn(1, _("User"));
Index: librapidsvn/include/log_dlg.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_dlg.hpp=09(revision 2)
+++ librapidsvn/include/log_dlg.hpp=09(revision 4)
@@ -25,6 +25,9 @@
 #ifndef _LOG_DLG_H_INCLUDED_
 #define _LOG_DLG_H_INCLUDED_
=20
+// stl
+#include <set>
+
 // wxWidgets
 #include "wx/dialog.h"
=20
@@ -83,7 +86,11 @@
=20
   void CheckControls();
   void UpdateSelection();
-
+  void ReduceSelectionToOnlyTwoItems();
+  void FillAffectedFiles();
+  std::set<std::string> GetIntersectionOfAffectedPaths();
+  std::list<svn::LogChangePathEntry> FilterAffectedPaths(std::list<svn::Lo=
gChangePathEntry> const & changedPaths, std::set<std::string> const & filte=
r);
+  std::set<std::string> GetAffectedPathsForItem(long itemIndex);
 };
=20
 #endif
Index: librapidsvn/include/log_aff_list.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_aff_list.hpp=09(revision 2)
+++ librapidsvn/include/log_aff_list.hpp=09(revision 4)
@@ -38,14 +38,14 @@
 #include "utils.hpp"
=20
=20
-class LogAffectedList : public wxListCtrl
+class LogAffectedList : public wxListView
 {
 public:
   LogAffectedList(wxWindow * parent, wxWindowID id, const wxPoint& pos =3D=
 wxDefaultPosition,=20
              const wxSize& size =3D wxDefaultSize, long style =3D wxLC_REP=
ORT,=20
              const wxValidator& validator =3D wxDefaultValidator,=20
              const wxString& name =3D wxT("LogAffectedList"))
-    : wxListCtrl(parent, id, pos, size, style, validator, name)
+    : wxListView(parent, id, pos, size, style, validator, name)
   {
     InsertColumn(0, _("Action"));
     InsertColumn(1, _("Path"));

------=_Part_17888_1497111811.1356103752063
Content-Type: text/x-diff; charset=us-ascii; 
	name=02_log_dialog_single_item_actions.diff
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; 
	filename=02_log_dialog_single_item_actions.diff

Index: librapidsvn/src/log_action.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/log_action.cpp=09(revision 4)
+++ librapidsvn/src/log_action.cpp=09(revision 6)
@@ -28,6 +28,8 @@
=20
 // svncpp
 #include "svncpp/client.hpp"
+#include "svncpp/info.hpp"
+#include "svncpp/repository_path.hpp"
 #include "svncpp/revision.hpp"
 #include "svncpp/status_selection.hpp"
=20
@@ -52,7 +54,7 @@
     client.log(target.c_str(), svn::Revision::START,
                svn::Revision::HEAD, true, false);
=20
-  LogData * data =3D new LogData(entries, target);
+  LogData * data =3D new LogData(entries, CreateRepositoryPath(client, tar=
get));
   ActionEvent::Post(GetParent(), TOKEN_LOG, data);
=20
   return true;
@@ -70,6 +72,13 @@
   return true;
 }
=20
+svn::RepositoryPath
+LogAction::CreateRepositoryPath(svn::Client & client, svn::Path & path)
+{
+  svn::InfoVector info =3D client.info(path, svn::Revision::START, svn::Re=
vision::HEAD);
+  std::string repositoryRoot =3D !info.empty() ? info.back().repos() : "";
+  return svn::RepositoryPath(path.path(), repositoryRoot);
+}
 /* -----------------------------------------------------------------
  * local variables:
  * eval: (load-file "../rapidsvn-dev.el")
Index: librapidsvn/src/utils.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/utils.cpp=09(revision 4)
+++ librapidsvn/src/utils.cpp=09(revision 6)
@@ -215,6 +215,15 @@
 }
=20
 void
+AppendLogItemQueryMenu(wxMenu *parentMenu)
+{
+  AppendMenuItem(parentMenu, ID_Diff, _("&Diff..."));
+  AppendMenuItem(parentMenu, ID_Edit, _("&View..."));
+  AppendMenuItem(parentMenu, ID_Log, _("&Log..."), EMBEDDED_BITMAP(log_png=
));
+  AppendMenuItem(parentMenu, ID_Annotate, _("&Annotate..."), EMBEDDED_BITM=
AP(annotate_png));
+}
+
+void
 AppendBookmarksMenu(wxMenu * parentMenu)
 {
   AppendMenuItem(*parentMenu, ID_AddWcBookmark);
@@ -317,6 +326,7 @@
=20
   case ID_Explore:
     caption =3D _("Explore...\tF2");
+    break;
   }
=20
   wxMenuItem * item =3D AppendMenuItem(&menu, id, caption, bitmap);
Index: librapidsvn/src/log_dlg.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/log_dlg.cpp=09(revision 4)
+++ librapidsvn/src/log_dlg.cpp=09(revision 6)
@@ -53,23 +53,24 @@
 public:
   const svn::LogEntries * entries;
   wxString path;
+  svn::RepositoryPath repositoryPath;=20
=20
 public:
-  Data(const char * path_,
+  Data(const svn::RepositoryPath & path_,
        const svn::LogEntries * entries_)
-      : entries(entries_), path(Utf8ToLocal(path_))
+      : entries(entries_), path(Utf8ToLocal(path_.c_str())), repositoryPat=
h(path_)
   {
   }
=20
 };
=20
 LogDlg::LogDlg(wxWindow * parent,
-               const char * path,
+               const svn::RepositoryPath & path,=20
                const svn::LogEntries * entries)
     : LogDlgBase(parent, -1, _("Log History"), wxDefaultPosition,
                  wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER |=
 wxMAXIMIZE_BOX)
 {
-  m =3D new Data(path, entries);
+  m =3D std::auto_ptr<Data>(new Data(path, entries));
=20
   m_staticRevisions->SetLabel(
     wxString::Format(_("History: %d revisions"), entries->size()));
@@ -84,12 +85,14 @@
   m_mainSizer->SetSizeHints(this);
   m_mainSizer->Fit(this);
=20
+  m_listFiles->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(=
LogDlg::OnAffectedFileOrDirCommand), NULL, this);
+
   CentreOnParent();
 }
=20
 LogDlg::~LogDlg()
 {
-  delete m;
+  m_listFiles->Disconnect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandl=
er(LogDlg::OnAffectedFileOrDirCommand), NULL, this);
 }
=20
 void
@@ -107,11 +110,17 @@
 void
 LogDlg::OnView(wxCommandEvent & WXUNUSED(event))
 {
+  OnView(m->path);
+}
+
+void
+LogDlg::OnView(wxString & path)
+{
   svn_revnum_t revnum =3D m_listRevisions->GetSelectedRevision();
=20
   GetData * data =3D new GetData();
   data->revision =3D revnum;
-  data->path =3D m->path;
+  data->path =3D path;
=20
   ActionEvent::Post(GetParent(), TOKEN_VIEW, data);
 }
@@ -119,13 +128,19 @@
 void
 LogDlg::OnDiff(wxCommandEvent & WXUNUSED(event))
 {
+  OnDiff(m->path);
+}
+
+void
+LogDlg::OnDiff(wxString & path, bool singleItemDiff)
+{
   RevnumArray array(m_listRevisions->GetSelectedRevisions());
=20
   wxASSERT(array.Count() >=3D 1);
   wxASSERT(array.Count() <=3D 2);
=20
   DiffData * data =3D new DiffData();
-  data->path =3D m->path;
+  data->path =3D path;
=20
   if (2 =3D=3D array.Count())
   {
@@ -133,6 +148,12 @@
     data->revision1 =3D svn::Revision(array[0]);
     data->revision2 =3D svn::Revision(array[1]);
   }
+  else if (m->repositoryPath.isUrl() || singleItemDiff)
+  {
+    data->compareType =3D DiffData::TWO_REVISIONS;
+    data->revision1 =3D svn::Revision(array[0]);
+    data->revision2 =3D svn::Revision(array[0] - 1);
+  }
   else=20
   {
     data->compareType =3D DiffData::WITH_DIFFERENT_REVISION;
@@ -168,18 +189,75 @@
 void
 LogDlg::OnAnnotate(wxCommandEvent & WXUNUSED(event))
 {
+  OnAnnotate(m->path);
+}
+
+void
+LogDlg::OnAnnotate(wxString & path)
+{
   RevnumArray array(m_listRevisions->GetSelectedRevisions());
=20
   wxASSERT(1 =3D=3D array.Count());
=20
   AnnotateData * data =3D new AnnotateData();
-  data->path =3D m->path;
+  data->path =3D path;
   data->endRevision =3D svn::Revision(array[0]);
=20
   ActionEvent::Post(GetParent(), TOKEN_ANNOTATE, data);
 }
=20
+void
+LogDlg::OnLog(wxString & path)
+{
+}
=20
+void
+LogDlg::OnAffectedFileOrDirRightClick(wxListEvent & event)
+{
+  long focusedIdx =3D m_listFiles->GetFocusedItem();
+
+  if (focusedIdx =3D=3D -1)
+  {
+    return;
+  }
+
+  wxMenu menu;
+  AppendLogItemQueryMenu(&menu);
+
+  m_listFiles->PopupMenu(&menu, event.GetPoint());
+}
+
+void
+LogDlg::OnAffectedFileOrDirCommand(wxCommandEvent & event)
+{
+  long focusedFileIdx =3D m_listFiles->GetFocusedItem();
+
+  wxASSERT(focusedFileIdx !=3D -1);
+
+  std::list<svn::LogChangePathEntry>::const_iterator it =3D affectedFiles.=
begin();
+  std::advance(it, focusedFileIdx);
+  wxString file(Utf8ToLocal(m->repositoryPath.getRepositoryRoot() + it->pa=
th));
+
+
+  int id =3D event.GetId();
+  switch (id)
+  {
+    case ID_Diff:
+      OnDiff(file, true);
+      break;
+    case ID_Edit:
+      OnView(file);
+      break;
+    case ID_Log:
+      OnLog(file);
+      break;
+    case ID_Annotate:
+      OnAnnotate(file);
+      break;
+  }
+}
+
+
 void=20
 LogDlg::UpdateSelection()
 {
@@ -189,7 +267,6 @@
   {
     m_textLog->Clear();
     ReduceSelectionToOnlyTwoItems();
-    FillAffectedFiles();
   }
   else
   {
@@ -200,8 +277,8 @@
     message.Trim();
=20
     m_textLog->SetValue(message);
-    m_listFiles->SetValue(entry.changedPaths);
   }
+  FillAffectedFiles();
   CheckControls();
 }
=20
@@ -279,6 +356,7 @@
 LogDlg::FillAffectedFiles()
 {
   m_listFiles->DeleteAllItems();
+  affectedFiles.clear();
=20
   long firstSelectedItemIndex =3D m_listRevisions->GetFirstSelected();
   if (firstSelectedItemIndex =3D=3D -1)
@@ -287,15 +365,15 @@
   }
=20
   const svn::LogEntry & entry =3D (*m->entries)[firstSelectedItemIndex];
-  std::list<svn::LogChangePathEntry> changedPaths =3D entry.changedPaths;
+  affectedFiles =3D entry.changedPaths;
=20
   if (m_listRevisions->GetSelectedItemCount() > 1)
   {
-    std::set<std::string> affectedPaths =3D GetIntersectionOfAffectedPaths=
();
-    changedPaths =3D FilterAffectedPaths(changedPaths, affectedPaths);
+    std::set<std::string> affectedFilesIntersection =3D GetIntersectionOfA=
ffectedPaths();
+    affectedFiles =3D FilterAffectedPaths(affectedFiles, affectedFilesInte=
rsection);
   }
=20
-  m_listFiles->SetValue(changedPaths);
+  m_listFiles->SetValue(affectedFiles);
 }
=20
 std::set<std::string>
Index: librapidsvn/src/main_frame.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/main_frame.cpp=09(revision 4)
+++ librapidsvn/src/main_frame.cpp=09(revision 6)
@@ -1887,7 +1887,7 @@
=20
     if (pData !=3D 0)
     {
-      LogDlg dlg(this, pData->target.c_str(), pData->logEntries);
+      LogDlg dlg(this, pData->target, pData->logEntries);
       dlg.ShowModal();
=20
       delete pData->logEntries;
Index: librapidsvn/src/rapidsvn_generated.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/rapidsvn_generated.cpp=09(revision 4)
+++ librapidsvn/src/rapidsvn_generated.cpp=09(revision 6)
@@ -1237,6 +1237,7 @@
 =09m_buttonDiff->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHand=
ler( LogDlgBase::OnDiff ), NULL, this );
 =09m_buttonMerge->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHan=
dler( LogDlgBase::OnMerge ), NULL, this );
 =09m_buttonAnnotate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEvent=
Handler( LogDlgBase::OnAnnotate ), NULL, this );
+=09m_listFiles->Connect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventH=
andler( LogDlgBase::OnAffectedFileOrDirRightClick ), NULL, this );
 }
=20
 LogDlgBase::~LogDlgBase()
@@ -1249,6 +1250,7 @@
 =09m_buttonDiff->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventH=
andler( LogDlgBase::OnDiff ), NULL, this );
 =09m_buttonMerge->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEvent=
Handler( LogDlgBase::OnMerge ), NULL, this );
 =09m_buttonAnnotate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEv=
entHandler( LogDlgBase::OnAnnotate ), NULL, this );
+=09m_listFiles->Disconnect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEve=
ntHandler( LogDlgBase::OnAffectedFileOrDirRightClick ), NULL, this );
 }
=20
 ImportDlgBase::ImportDlgBase( wxWindow* parent, wxWindowID id, const wxStr=
ing& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog=
( parent, id, title, pos, size, style )
Index: librapidsvn/src/rapidsvn.fbp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/rapidsvn.fbp=09(revision 4)
+++ librapidsvn/src/rapidsvn.fbp=09(revision 6)
@@ -10617,7 +10617,7 @@
                                                                 <event nam=
e=3D"OnListItemDeselected"></event>
                                                                 <event nam=
e=3D"OnListItemFocused"></event>
                                                                 <event nam=
e=3D"OnListItemMiddleClick"></event>
-                                                                <event nam=
e=3D"OnListItemRightClick"></event>
+                                                                <event nam=
e=3D"OnListItemRightClick">OnAffectedFileOrDirRightClick</event>
                                                                 <event nam=
e=3D"OnListItemSelected"></event>
                                                                 <event nam=
e=3D"OnListKeyDown"></event>
                                                                 <event nam=
e=3D"OnMiddleDClick"></event>
Index: librapidsvn/include/rapidsvn_generated.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/rapidsvn_generated.h=09(revision 4)
+++ librapidsvn/include/rapidsvn_generated.h=09(revision 6)
@@ -599,6 +599,7 @@
 =09=09virtual void OnDiff( wxCommandEvent& event ) { event.Skip(); }
 =09=09virtual void OnMerge( wxCommandEvent& event ) { event.Skip(); }
 =09=09virtual void OnAnnotate( wxCommandEvent& event ) { event.Skip(); }
+=09=09virtual void OnAffectedFileOrDirRightClick( wxListEvent& event ) { e=
vent.Skip(); }
 =09=09
 =09
 =09public:
Index: librapidsvn/include/log_dlg.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_dlg.hpp=09(revision 4)
+++ librapidsvn/include/log_dlg.hpp=09(revision 6)
@@ -27,12 +27,14 @@
=20
 // stl
 #include <set>
+#include <memory>
=20
 // wxWidgets
 #include "wx/dialog.h"
=20
 // svncpp
 #include "svncpp/client.hpp"
+#include "svncpp/repository_path.hpp"
=20
 // app
 #include "rapidsvn_generated.h"
@@ -49,7 +51,7 @@
    * @param entries log entries
    */
   LogDlg(wxWindow * parent,
-         const char * path,
+         const svn::RepositoryPath & path,=20
          const svn::LogEntries * entries);
=20
   /**
@@ -79,11 +81,23 @@
   void
   OnRevDeselected(wxListEvent & event);
=20
+  void
+  OnAffectedFileOrDirRightClick(wxListEvent & event);
+
 private:
   /** hide implementation details */
   struct Data;
-  Data * m;
+  std::auto_ptr<Data> m;
+ =20
+  std::list<svn::LogChangePathEntry> affectedFiles;
=20
+  void OnAffectedFileOrDirCommand(wxCommandEvent & event);
+
+  void OnView(wxString & path);
+  void OnDiff(wxString & path, bool singleItemDiff =3D false);
+  void OnAnnotate(wxString & path);
+  void OnLog(wxString & path);
+
   void CheckControls();
   void UpdateSelection();
   void ReduceSelectionToOnlyTwoItems();
Index: librapidsvn/include/log_action.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_action.hpp=09(revision 4)
+++ librapidsvn/include/log_action.hpp=09(revision 6)
@@ -32,6 +32,9 @@
 namespace svn
 {
   class StatusSel;
+  class Client;
+  class Path;
+  class RepositoryPath;
 }
=20
 class LogAction : public Action
@@ -47,6 +50,9 @@
=20
   static bool
   CheckStatusSel(const svn::StatusSel & statusSel);
+
+private:
+  svn::RepositoryPath CreateRepositoryPath(svn::Client & client, svn::Path=
 & path);
 };
=20
 #endif
Index: librapidsvn/include/log_data.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/log_data.hpp=09(revision 4)
+++ librapidsvn/include/log_data.hpp=09(revision 6)
@@ -30,14 +30,15 @@
=20
 // svncpp
 #include "svncpp/client.hpp"
+#include "svncpp/repository_path.hpp"
=20
 struct LogData
 {
 public:
   const svn::LogEntries * logEntries;
-  svn::Path target;
+  svn::RepositoryPath target;
=20
-  LogData(const svn::LogEntries * logEntries_, const svn::Path & target_)
+  LogData(const svn::LogEntries * logEntries_, const svn::RepositoryPath &=
 target_)
       : logEntries(logEntries_), target(target_)
   {
   }
Index: librapidsvn/include/utils.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/include/utils.hpp=09(revision 4)
+++ librapidsvn/include/utils.hpp=09(revision 6)
@@ -117,6 +117,13 @@
 void
 AppendQueryMenu(wxMenu * parentMenu);
=20
+/**
+ * Append entries for the "Query" menu for log item.
+ *
+ * @param parentMenu menu that will receive the items
+ */
+void
+AppendLogItemQueryMenu(wxMenu *parentMenu);
=20
 /**
  * Append entries for "verbs" (Win32 only).
Index: libsvncpp/include/svncpp/repository_path.hpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- libsvncpp/include/svncpp/repository_path.hpp=09(revision 0)
+++ libsvncpp/include/svncpp/repository_path.hpp=09(revision 6)
@@ -0,0 +1,111 @@
+/*
+ * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+ * Copyright (c) 2002-2012 The RapidSVN Group.  All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the file GPL.txt.
+ * If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://rapidsvn.tigris.org/.
+ * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
+ */
+
+#ifndef _SVNCPP_REPOSITORY_PATH_HPP_
+#define _SVNCPP_REPOSITORY_PATH_HPP_
+
+#include "svncpp/path.hpp"
+
+namespace svn
+{
+  /**
+   * Encapsulation for Subversion Path handling with repository root.
+   */
+  class RepositoryPath : public Path
+  {
+  private:
+    std::string m_repositoryRoot;
+
+    RepositoryPath(const Path &) {}
+    Path& operator=3D (const Path & path) {}
+
+  public:
+    /**
+     * Constructor that takes a path as parameter
+     * and also repository root path.
+     * Both strings are converted to subversion internal
+     * representation. The string are copied.
+     *
+     * @param path RepositoryPath string
+     * @param repositoryRoot RepositoryPath string
+     */
+    RepositoryPath(const std::string & path =3D "", const std::string & re=
positoryRoot =3D "")
+      : Path(path), m_repositoryRoot(repositoryRoot) {}
+
+    /**
+     * Constructor
+     *
+     * @see RepositoryPath::RepositoryPath (const std::string &, const std=
::string &)
+     * @param path RepositoryPath string
+     * @param repositoryRoot RepositoryPath string
+     */
+    RepositoryPath(const char * path, const char * repositoryRoot)
+      : Path(path), m_repositoryRoot(repositoryRoot !=3D NULL ? repository=
Root : "") {}
+
+    /**
+     * Copy constructor
+     *
+     * @param path RepositoryPath to be copied
+     */
+    RepositoryPath(const RepositoryPath & path)
+      : Path(path), m_repositoryRoot(path.getRepositoryRoot()) {}
+
+    /**
+     * Assignment operator
+     */
+    RepositoryPath& operator=3D (const RepositoryPath & path)
+    {
+      if (this =3D=3D &path)
+        return *this;
+     =20
+      Path(*this) =3D path;
+      m_repositoryRoot =3D path.getRepositoryRoot();
+
+      return *this;
+    }
+
+    /**
+     * Comparison operator
+     */
+    bool
+    operator=3D=3D (const RepositoryPath & path) const
+    {
+      return Path(*this) =3D=3D path && m_repositoryRoot =3D=3D path.getRe=
positoryRoot();
+    }
+
+    /** returns repository root of subversion, which contains this path */
+    std::string
+    getRepositoryRoot() const
+    {
+      return m_repositoryRoot;
+    }
+  };
+}
+
+#endif
+/* -----------------------------------------------------------------
+ * local variables:
+ * eval: (load-file "../../rapidsvn-dev.el")
+ * end:
+ */
Index: libsvncpp/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- libsvncpp/Makefile.am=09(revision 4)
+++ libsvncpp/Makefile.am=09(revision 6)
@@ -16,6 +16,7 @@
 =09include/svncpp/path.hpp \
 =09include/svncpp/pool.hpp \
 =09include/svncpp/property.hpp \
+=09include/svncpp/repository_path.hpp \
 =09include/svncpp/revision.hpp \
 =09include/svncpp/status.hpp \
 =09include/svncpp/status_selection.hpp \

------=_Part_17888_1497111811.1356103752063
Content-Type: text/x-diff; charset=us-ascii; 
	name=03_log_dialog_wxlistview_fix.diff
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=03_log_dialog_wxlistview_fix.diff

Index: librapidsvn/src/log_dlg.cpp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- librapidsvn/src/log_dlg.cpp=09(revision 6)
+++ librapidsvn/src/log_dlg.cpp=09(working copy)
@@ -270,7 +270,7 @@
   }
   else
   {
-    long itemIndex =3D m_listRevisions->GetNextItem(-1, wxLIST_NEXT_ALL, w=
xLIST_STATE_SELECTED);
+    long itemIndex =3D m_listRevisions->GetFirstSelected();
     const svn::LogEntry & entry =3D (*m->entries)[itemIndex];
=20
     wxString message(Utf8ToLocal(entry.message.c_str()));

------=_Part_17888_1497111811.1356103752063--

------=_Part_17887_1057412048.1356103752063
Content-Type: application/pgp-signature; name=signature.asc
Content-Transfer-Encoding: 7bit
Content-Description: Digital signature
Content-Disposition: attachment; filename=signature.asc

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iEYEARECAAYFAlDUWYYACgkQqyAtJTO7yRI8XgCgibG5kxaORvsgwN1Ybjxb5UC4
uLkAoIBHu/oGjkDV+dzBkAjYVfcp9Oab
=9dCt
-----END PGP SIGNATURE-----

------=_Part_17887_1057412048.1356103752063--