{"thread":{"id":"16989","subject":"[EGIT PATCH] Sorting commit items by click on the table header in commit dialog.","startedAt":"2009-01-04T22:46:47Z","lastAt":"2009-01-06T00:49:07Z","messageCount":3,"participants":["Vasyl' Vavrychuk","Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"99335","messageId":"gjre95$4cs$1@ger.gmane.org","threadId":"16989","inReplyTo":null,"subject":"[EGIT PATCH] Sorting commit items by click on the table header in commit dialog.","fromName":"Vasyl' Vavrychuk","fromEmail":"vvavrychuk@gmail.com","sentAt":"2009-01-04T22:46:47Z","receivedAt":"2009-01-04T22:46:47Z","isPatch":true,"sender":{"key":"vvavrychuk@gmail.com","avatar":"https://avatars.githubusercontent.com/u/152563?v=4"},"body":"In order to implement new feature I have replaced class associated with every table row.\nCommitItem class encapsulate data that commit dialog manipulates with.\nComparators are written using idiom from http://tobega.blogspot.com/2008/05/beautiful-enums.html.\nClicks on a certain column are handled in HeaderSelectionListener class.\n\nSigned-off-by: Vasyl Vavrychuk <vvavrychuk@gmail.com>\n---\n .../egit/ui/internal/actions/CommitAction.java     |    2 +-\n .../egit/ui/internal/dialogs/CommitDialog.java     |  248 ++++++++++++++------\n 2 files changed, 176 insertions(+), 74 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CommitAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CommitAction.java\nindex d703048..779596c 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CommitAction.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/CommitAction.java\n@@ -139,7 +139,7 @@ private void loadPreviousCommit() {\n \tprivate void performCommit(CommitDialog commitDialog, String commitMessage)\n \t\t\tthrows TeamException {\n \t\t// System.out.println(\"Commit Message: \" + commitMessage);\n-\t\tIFile[] selectedItems = commitDialog.getSelectedItems();\n+\t\tIFile[] selectedItems = commitDialog.getSelectedFiles();\n \n \t\tHashMap<Repository, Tree> treeMap = new HashMap<Repository, Tree>();\n \t\ttry {\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java\nindex 4f932f2..a0598ff 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/dialogs/CommitDialog.java\n@@ -15,6 +15,7 @@\n import java.io.IOException;\n import java.util.ArrayList;\n import java.util.Collections;\n+import java.util.Comparator;\n import java.util.Iterator;\n \n import org.eclipse.core.resources.IFile;\n@@ -28,9 +29,11 @@\n import org.eclipse.jface.viewers.IStructuredSelection;\n import org.eclipse.jface.viewers.ITableLabelProvider;\n import org.eclipse.jface.viewers.Viewer;\n+import org.eclipse.jface.viewers.ViewerComparator;\n import org.eclipse.swt.SWT;\n import org.eclipse.swt.events.KeyAdapter;\n import org.eclipse.swt.events.KeyEvent;\n+import org.eclipse.swt.events.SelectionAdapter;\n import org.eclipse.swt.events.SelectionEvent;\n import org.eclipse.swt.events.SelectionListener;\n import org.eclipse.swt.graphics.Image;\n@@ -62,56 +65,38 @@\n  */\n public class CommitDialog extends Dialog {\n \n+\tclass CommitContentProvider implements IStructuredContentProvider {\n+\n+\t\tpublic void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\n+\t\t\t// Empty\n+\t\t}\n+\n+\t\tpublic void dispose() {\n+\t\t\t// Empty\n+\t\t}\n+\n+\t\tpublic Object[] getElements(Object inputElement) {\n+\t\t\treturn items.toArray();\n+\t\t}\n+\n+\t}\n+\n \tclass CommitLabelProvider extends WorkbenchLabelProvider implements\n \t\t\tITableLabelProvider {\n \t\tpublic String getColumnText(Object obj, int columnIndex) {\n-\t\t\tIFile file = (IFile) obj;\n-\t\t\tif (columnIndex == 1)\n-\t\t\t\treturn file.getProject().getName() + \": \"\n-\t\t\t\t\t\t+ file.getProjectRelativePath();\n+\t\t\tCommitItem item = (CommitItem) obj;\n \n-\t\t\telse if (columnIndex == 0) {\n-\t\t\t\tString prefix = \"Unknown\";\n+\t\t\tswitch (columnIndex) {\n+\t\t\tcase 0:\n+\t\t\t\treturn item.status;\n \n-\t\t\t\ttry {\n-\t\t\t\t\tRepositoryMapping repositoryMapping = RepositoryMapping.getMapping(file.getProject());\n-\n-\t\t\t\t\tRepository repo = repositoryMapping.getRepository();\n-\t\t\t\t\tGitIndex index = repo.getIndex();\n-\t\t\t\t\tTree headTree = repo.mapTree(\"HEAD\");\n-\n-\t\t\t\t\tString repoPath = repositoryMapping\n-\t\t\t\t\t\t\t.getRepoRelativePath(file);\n-\t\t\t\t\tTreeEntry headEntry = headTree.findBlobMember(repoPath);\n-\t\t\t\t\tboolean headExists = headTree.existsBlob(repoPath);\n-\n-\t\t\t\t\tEntry indexEntry = index.getEntry(repoPath);\n-\t\t\t\t\tif (headEntry == null) {\n-\t\t\t\t\t\tprefix = \"Added\";\n-\t\t\t\t\t\tif (indexEntry.isModified(repositoryMapping.getWorkDir()))\n-\t\t\t\t\t\t\tprefix = \"Added, index diff\";\n-\t\t\t\t\t} else if (indexEntry == null) {\n-\t\t\t\t\t\tprefix = \"Removed\";\n-\t\t\t\t\t} else if (headExists\n-\t\t\t\t\t\t\t&& !headEntry.getId().equals(\n-\t\t\t\t\t\t\t\t\tindexEntry.getObjectId())) {\n-\t\t\t\t\t\tprefix = \"Modified\";\n-\n-\n-\t\t\t\t\t\tif (indexEntry.isModified(repositoryMapping.getWorkDir()))\n-\t\t\t\t\t\t\tprefix = \"Mod., index diff\";\n-\t\t\t\t\t} else if (!new File(repositoryMapping.getWorkDir(), indexEntry.getName()).isFile()) {\n-\t\t\t\t\t\tprefix = \"Rem., not staged\";\n-\t\t\t\t\t} else if (indexEntry.isModified(repositoryMapping.getWorkDir())) {\n-\t\t\t\t\t\tprefix = \"Mod., not staged\";\n-\t\t\t\t\t}\n-\n-\t\t\t\t} catch (Exception e) {\n-\t\t\t\t}\n+\t\t\tcase 1:\n+\t\t\t\treturn item.file.getProject().getName() + \": \"\n+\t\t\t\t\t\t+ item.file.getProjectRelativePath();\n \n-\t\t\t\treturn prefix;\n+\t\t\tdefault:\n+\t\t\t\treturn null;\n \t\t\t}\n-\t\t\treturn null;\n \t\t}\n \n \t\tpublic Image getColumnImage(Object element, int columnIndex) {\n@@ -121,7 +106,7 @@ public Image getColumnImage(Object element, int columnIndex) {\n \t\t}\n \t}\n \n-\tArrayList<IFile> files;\n+\tArrayList<CommitItem> items = new ArrayList<CommitItem>();\n \n \t/**\n \t * @param parentShell\n@@ -227,30 +212,17 @@ public void widgetDefaultSelected(SelectionEvent arg0) {\n \t\tTableColumn statCol = new TableColumn(resourcesTable, SWT.LEFT);\n \t\tstatCol.setText(\"Status\");\n \t\tstatCol.setWidth(150);\n+\t\tstatCol.addSelectionListener(new HeaderSelectionListener(CommitItem.Order.ByStatus));\n \n \t\tTableColumn resourceCol = new TableColumn(resourcesTable, SWT.LEFT);\n \t\tresourceCol.setText(\"File\");\n \t\tresourceCol.setWidth(415);\n+\t\tresourceCol.addSelectionListener(new HeaderSelectionListener(CommitItem.Order.ByFile));\n \n \t\tfilesViewer = new CheckboxTableViewer(resourcesTable);\n-\t\tfilesViewer.setContentProvider(new IStructuredContentProvider() {\n-\n-\t\t\tpublic void inputChanged(Viewer viewer, Object oldInput,\n-\t\t\t\t\tObject newInput) {\n-\t\t\t\t// Empty\n-\t\t\t}\n-\n-\t\t\tpublic void dispose() {\n-\t\t\t\t// Empty\n-\t\t\t}\n-\n-\t\t\tpublic Object[] getElements(Object inputElement) {\n-\t\t\t\treturn files.toArray();\n-\t\t\t}\n-\n-\t\t});\n+\t\tfilesViewer.setContentProvider(new CommitContentProvider());\n \t\tfilesViewer.setLabelProvider(new CommitLabelProvider());\n-\t\tfilesViewer.setInput(files);\n+\t\tfilesViewer.setInput(items);\n \t\tfilesViewer.setAllChecked(true);\n \t\tfilesViewer.getTable().setMenu(getContextMenu());\n \n@@ -271,15 +243,15 @@ public void handleEvent(Event arg0) {\n \t\t\t\ttry {\n \t\t\t\t\tArrayList<GitIndex> changedIndexes = new ArrayList<GitIndex>();\n \t\t\t\t\tfor (Iterator<Object> it = sel.iterator(); it.hasNext();) {\n-\t\t\t\t\t\tIFile file = (IFile) it.next();\n+\t\t\t\t\t\tCommitItem commitItem = (CommitItem) it.next();\n \n-\t\t\t\t\t\tIProject project = file.getProject();\n+\t\t\t\t\t\tIProject project = commitItem.file.getProject();\n \t\t\t\t\t\tRepositoryMapping map = RepositoryMapping.getMapping(project);\n \n \t\t\t\t\t\tRepository repo = map.getRepository();\n \t\t\t\t\t\tGitIndex index = null;\n \t\t\t\t\t\tindex = repo.getIndex();\n-\t\t\t\t\t\tEntry entry = index.getEntry(map.getRepoRelativePath(file));\n+\t\t\t\t\t\tEntry entry = index.getEntry(map.getRepoRelativePath(commitItem.file));\n \t\t\t\t\t\tif (entry != null && entry.isModified(map.getWorkDir())) {\n \t\t\t\t\t\t\tentry.update(new File(map.getWorkDir(), entry.getName()));\n \t\t\t\t\t\t\tif (!changedIndexes.contains(index))\n@@ -302,6 +274,47 @@ public void handleEvent(Event arg0) {\n \t\treturn menu;\n \t}\n \n+\tprivate static String getFileStatus(IFile file) {\n+\t\tString prefix = \"Unknown\";\n+\n+\t\ttry {\n+\t\t\tRepositoryMapping repositoryMapping = RepositoryMapping\n+\t\t\t\t\t.getMapping(file.getProject());\n+\n+\t\t\tRepository repo = repositoryMapping.getRepository();\n+\t\t\tGitIndex index = repo.getIndex();\n+\t\t\tTree headTree = repo.mapTree(\"HEAD\");\n+\n+\t\t\tString repoPath = repositoryMapping.getRepoRelativePath(file);\n+\t\t\tTreeEntry headEntry = headTree.findBlobMember(repoPath);\n+\t\t\tboolean headExists = headTree.existsBlob(repoPath);\n+\n+\t\t\tEntry indexEntry = index.getEntry(repoPath);\n+\t\t\tif (headEntry == null) {\n+\t\t\t\tprefix = \"Added\";\n+\t\t\t\tif (indexEntry.isModified(repositoryMapping.getWorkDir()))\n+\t\t\t\t\tprefix = \"Added, index diff\";\n+\t\t\t} else if (indexEntry == null) {\n+\t\t\t\tprefix = \"Removed\";\n+\t\t\t} else if (headExists\n+\t\t\t\t\t&& !headEntry.getId().equals(indexEntry.getObjectId())) {\n+\t\t\t\tprefix = \"Modified\";\n+\n+\t\t\t\tif (indexEntry.isModified(repositoryMapping.getWorkDir()))\n+\t\t\t\t\tprefix = \"Mod., index diff\";\n+\t\t\t} else if (!new File(repositoryMapping.getWorkDir(), indexEntry\n+\t\t\t\t\t.getName()).isFile()) {\n+\t\t\t\tprefix = \"Rem., not staged\";\n+\t\t\t} else if (indexEntry.isModified(repositoryMapping.getWorkDir())) {\n+\t\t\t\tprefix = \"Mod., not staged\";\n+\t\t\t}\n+\n+\t\t} catch (Exception e) {\n+\t\t}\n+\n+\t\treturn prefix;\n+\t}\n+\n \t/**\n \t * @return The message the user entered\n \t */\n@@ -323,7 +336,7 @@ public void setCommitMessage(String s) {\n \tprivate boolean amending = false;\n \tprivate boolean amendAllowed = true;\n \n-\tprivate ArrayList<IFile> selectedItems = new ArrayList<IFile>();\n+\tprivate ArrayList<IFile> selectedFiles = new ArrayList<IFile>();\n \tprivate String previousCommitMessage = \"\";\n \n \t/**\n@@ -331,15 +344,51 @@ public void setCommitMessage(String s) {\n \t *\n \t * @param items\n \t */\n-\tpublic void setSelectedItems(IFile[] items) {\n-\t\tCollections.addAll(selectedItems, items);\n+\tpublic void setSelectedFiles(IFile[] items) {\n+\t\tCollections.addAll(selectedFiles, items);\n \t}\n \n \t/**\n \t * @return the resources selected by the user to commit.\n \t */\n-\tpublic IFile[] getSelectedItems() {\n-\t\treturn selectedItems.toArray(new IFile[0]);\n+\tpublic IFile[] getSelectedFiles() {\n+\t\treturn selectedFiles.toArray(new IFile[0]);\n+\t}\n+\n+\tclass HeaderSelectionListener extends SelectionAdapter {\n+\n+\t\tprivate CommitItem.Order order;\n+\n+\t\tprivate boolean reversed;\n+\n+\t\tpublic HeaderSelectionListener(CommitItem.Order order) {\n+\t\t\tthis.order = order;\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void widgetSelected(SelectionEvent e) {\n+\t\t\tTableColumn column = (TableColumn)e.widget;\n+\t\t\tTable table = column.getParent();\n+\n+\t\t\tif (column == table.getSortColumn()) {\n+\t\t\t\treversed = !reversed;\n+\t\t\t} else {\n+\t\t\t\treversed = false;\n+\t\t\t}\n+\t\t\ttable.setSortColumn(column);\n+\n+\t\t\tComparator<CommitItem> comparator;\n+\t\t\tif (reversed) {\n+\t\t\t\tcomparator = order.descending();\n+\t\t\t\ttable.setSortDirection(SWT.DOWN);\n+\t\t\t} else {\n+\t\t\t\tcomparator = order;\n+\t\t\t\ttable.setSortDirection(SWT.UP);\n+\t\t\t}\n+\n+\t\t\tfilesViewer.setComparator(new CommitViewerComparator(comparator));\n+\t\t}\n+\n \t}\n \n \t@Override\n@@ -350,9 +399,9 @@ protected void okPressed() {\n \t\tamending = amendingButton.getSelection();\n \t\t\n \t\tObject[] checkedElements = filesViewer.getCheckedElements();\n-\t\tselectedItems.clear();\n+\t\tselectedFiles.clear();\n \t\tfor (Object obj : checkedElements)\n-\t\t\tselectedItems.add((IFile) obj);\n+\t\t\tselectedFiles.add(((CommitItem) obj).file);\n \n \t\tif (commitMessage.trim().length() == 0) {\n \t\t\tMessageDialog.openWarning(getShell(), \"No message\", \"You must enter a commit message\");\n@@ -368,7 +417,7 @@ protected void okPressed() {\n \t\t\t}\n \t\t} else author = null;\n \n-\t\tif (selectedItems.isEmpty() && !amending) {\n+\t\tif (selectedFiles.isEmpty() && !amending) {\n \t\t\tMessageDialog.openWarning(getShell(), \"No items selected\", \"No items are currently selected to be committed.\");\n \t\t\treturn;\n \t\t}\n@@ -382,7 +431,13 @@ protected void okPressed() {\n \t * @param files potentially affected by a new commit\n \t */\n \tpublic void setFileList(ArrayList<IFile> files) {\n-\t\tthis.files = files;\n+\t\titems.clear();\n+\t\tfor (IFile file : files) {\n+\t\t\tCommitItem item = new CommitItem();\n+\t\t\titem.status = getFileStatus(file);\n+\t\t\titem.file = file;\n+\t\t\titems.add(item);\n+\t\t}\n \t}\n \n \t@Override\n@@ -468,3 +523,50 @@ protected int getShellStyle() {\n \t\treturn super.getShellStyle() | SWT.RESIZE;\n \t}\n }\n+\n+class CommitItem {\n+\tString status;\n+\n+\tIFile file;\n+\n+\tpublic static enum Order implements Comparator<CommitItem> {\n+\t\tByStatus() {\n+\n+\t\t\tpublic int compare(CommitItem o1, CommitItem o2) {\n+\t\t\t\treturn o1.status.compareTo(o2.status);\n+\t\t\t}\n+\n+\t\t},\n+\n+\t\tByFile() {\n+\n+\t\t\tpublic int compare(CommitItem o1, CommitItem o2) {\n+\t\t\t\treturn o1.file.getProjectRelativePath().toString().\n+\t\t\t\t\tcompareTo(o2.file.getProjectRelativePath().toString());\n+\t\t\t}\n+\n+\t\t};\n+\n+\t\tpublic Comparator<CommitItem> ascending() {\n+\t\t\treturn this;\n+\t\t}\n+\n+\t\tpublic Comparator<CommitItem> descending() {\n+\t\t\treturn Collections.reverseOrder(this);\n+\t\t}\n+\t}\n+}\n+\n+class CommitViewerComparator extends ViewerComparator {\n+\n+\tpublic CommitViewerComparator(Comparator comparator){\n+\t\tsuper(comparator);\n+\t}\n+\n+\t@SuppressWarnings(\"unchecked\")\n+\t@Override\n+\tpublic int compare(Viewer viewer, Object e1, Object e2) {\n+\t\treturn getComparator().compare(e1, e2);\n+\t}\n+\n+}\n-- \n1.5.6.1.1071.g76fb\n"},{"id":"99354","messageId":"200901050835.20038.robin.rosenberg.lists@dewire.com","threadId":"16989","inReplyTo":"gjre95$4cs$1@ger.gmane.org","subject":"Re: [EGIT PATCH] Sorting commit items by click on the table header in commit dialog.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2009-01-05T07:35:19Z","receivedAt":"2009-01-05T07:35:19Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"söndag 04 januari 2009 23:46:47 skrev Vasyl' Vavrychuk:\n> In order to implement new feature I have replaced class associated with every table row.\n> CommitItem class encapsulate data that commit dialog manipulates with.\n> Comparators are written using idiom from http://tobega.blogspot.com/2008/05/beautiful-enums.html.\n> Clicks on a certain column are handled in HeaderSelectionListener class.\n\nHmm. This one cannot be applied on top of master. There is only only one commit on Dec 8\nthat involves the same file, so If you could rebase that would be nice. Other than that it looks ok.\n\nPlease also Cc me and Shawn on patches to reduce the risk of them getting lost.\n\n-- robin\n"},{"id":"99393","messageId":"200901060149.07892.robin.rosenberg.lists@dewire.com","threadId":"16989","inReplyTo":"200901050835.20038.robin.rosenberg.lists@dewire.com","subject":"Re: [EGIT PATCH] Sorting commit items by click on the table header in commit dialog.","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2009-01-06T00:49:07Z","receivedAt":"2009-01-06T00:49:07Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"\nSeems this was trivial to apply after patchin the patch, so I did.\n\n-- robin\n"}]}