Skip to content

Commit

Permalink
browse: add drag-and-drop for external applications
Browse files Browse the repository at this point in the history
Allow dragging from the browse widget into external applications.

Related-to: git-cola#335

Signed-off-by: David Aguilar <davvid@gmail.com>
  • Loading branch information
davvid committed Aug 2, 2014
1 parent 0a56d37 commit 5cfb6bb
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 15 deletions.
9 changes: 8 additions & 1 deletion cola/models/browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def text(cls, column):

class GitRepoModel(QtGui.QStandardItemModel):
"""Provides an interface into a git repository for browsing purposes."""

def __init__(self, parent):
QtGui.QStandardItemModel.__init__(self, parent)
self._interesting_paths = self._get_paths()
Expand All @@ -67,6 +68,11 @@ def __init__(self, parent):
self._direntries = {'': self.invisibleRootItem()}
self._initialize()

def mimeData(self, indexes):
paths = qtutils.paths_from_indexes(self, indexes,
item_type=GitRepoNameItem.TYPE)
return qtutils.mimedata_from_paths(paths)

def _create_column(self, col, path):
"""Creates a StandardItem for use in a treeview cell."""
# GitRepoNameItem is the only one that returns a custom type(),
Expand Down Expand Up @@ -413,8 +419,8 @@ class GitRepoItem(QtGui.QStandardItem):
"""
def __init__(self, column, path):
QtGui.QStandardItem.__init__(self)
self.setEditable(False)
self.setDragEnabled(False)
self.setEditable(False)
entry = GitRepoEntryManager.entry(path)
if column == Columns.STATUS:
QtCore.QObject.connect(entry, SIGNAL(column), self.set_status)
Expand All @@ -437,6 +443,7 @@ class GitRepoNameItem(GitRepoItem):
def __init__(self, path):
GitRepoItem.__init__(self, Columns.NAME, path)
self.path = path
self.setDragEnabled(True)

def type(self):
"""
Expand Down
37 changes: 34 additions & 3 deletions cola/qtutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,42 @@ def create_listwidget_item(text, filename):

class TreeWidgetItem(QtGui.QTreeWidgetItem):

def __init__(self, text, filename, exists):
TYPE = QtGui.QStandardItem.UserType + 101

def __init__(self, path, icon, exists):
QtGui.QTreeWidgetItem.__init__(self)
self.path = path
self.exists = exists
self.setIcon(0, cached_icon_from_path(filename))
self.setText(0, text)
self.setIcon(0, cached_icon_from_path(icon))
self.setText(0, path)

def type(self):
return self.TYPE


def create_treewidget_item(text, filename, exists=True):
"""Creates a QTreeWidgetItem with text and the icon at filename."""
return TreeWidgetItem(text, filename, exists)


def paths_from_indexes(model, indexes,
item_type=TreeWidgetItem.TYPE,
item_filter=None):
"""Return paths from a list of QStandardItemModel indexes"""
items = [model.itemFromIndex(i) for i in indexes]
return paths_from_items(items, item_type=item_type, item_filter=item_filter)


def paths_from_items(items,
item_type=TreeWidgetItem.TYPE,
item_filter=None):
"""Return a list of paths from a list of items"""
if item_filter is None:
item_filter = lambda x: True
return [i.path for i in items
if i.type() == item_type and item_filter(i)]


@memoize
def cached_icon_from_path(filename):
return QtGui.QIcon(filename)
Expand Down Expand Up @@ -689,6 +713,13 @@ def create_toolbutton(text=None, layout=None, tooltip=None, icon=None):
return button


def mimedata_from_paths(paths):
"""Return mimedata with a list of absolute path URLs"""
urls = [QtCore.QUrl(core.abspath(path)) for path in paths]
mimedata = QtCore.QMimeData()
mimedata.setUrls(urls)
return mimedata

# Syntax highlighting

def TERMINAL(pattern):
Expand Down
9 changes: 6 additions & 3 deletions cola/widgets/browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class RepoTreeView(standard.TreeView):
def __init__(self, parent):
standard.TreeView.__init__(self, parent)

self.setDragEnabled(True)
self.setRootIsDecorated(True)
self.setSortingEnabled(False)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
Expand Down Expand Up @@ -246,11 +247,13 @@ def item_from_index(self, model_index):
index = model_index.sibling(model_index.row(), 0)
return self.model().itemFromIndex(index)

def paths_from_indexes(self, indexes):
return qtutils.paths_from_indexes(self.model(), indexes,
item_type=GitRepoNameItem.TYPE)

def selected_paths(self):
"""Return the selected paths."""
items = map(self.model().itemFromIndex, self.selectedIndexes())
return [i.path for i in items
if i.type() == GitRepoNameItem.TYPE]
return self.paths_from_indexes(self.selectedIndexes())

def selected_staged_paths(self, selection=None):
"""Return selected staged paths."""
Expand Down
11 changes: 4 additions & 7 deletions cola/widgets/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,10 +891,7 @@ def copy_path(self):
filename = selection.selection_model().filename()
qtutils.copy_path(filename)

def mimeData(self, indexes):
"""Add a list of selected files to the mime data"""
urls = [QtCore.QUrl(core.abspath(path))
for path in selection.union(self.selection())]
mimedata = QtCore.QMimeData()
mimedata.setUrls(urls)
return mimedata
def mimeData(self, items):
"""Return a list of absolute-path URLs"""
paths = qtutils.paths_from_items(items, item_filter=lambda x: x.exists)
return qtutils.mimedata_from_paths(paths)
3 changes: 2 additions & 1 deletion share/doc/git-cola/relnotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Usability, bells and whistles
-----------------------------
* Updated Brazillian Portuguese translation.

* The status widget now allows drag and drop into external applications.
* The status and browse widgets now allow drag-and-drop into
external applications.

https://github.com/git-cola/git-cola/issue/335

Expand Down

0 comments on commit 5cfb6bb

Please sign in to comment.