It's not monthly, so it's safe. Basically the story of Swing.
5 things to do for line-by-line stage / unstage
1. Output diff as the original patch
2. Select the line you want to stage / unstage
3. Edit the body of hunk``
4. Recalculate the hunk header``
5. Apply the final patch
It was impossible to use JGit, so I talked about using git.exe.
3. Edit the body of hunk``
4. Recalculate the hunk header``
1. Output diff as the original patch
2. Select the line you want to stage / unstage
However, it must be displayed in order to be selected. This time, it's about display.
As a GUI application
It seems that it is necessary to reflect such things in the design, I'm not basically thinking about it here. I want to make "my git, which I thought about"
Just think about it and be happy.
The first thing I imagined was A collection-type view with sections like the iOS UITableView. But you and Java, this is the JVM.
As a UI for partial selection of diff with Swing quickly I chose JList because it seems to be the easiest. The diffs that are the source of the patch are displayed in a list line by line and selected.
I wanted to update row by row, so I made it JTable (described later), Since it is a JTable with only one column, the basic usage is the same.
By the way, even if you display it in a list, you don't have to display the diff line by line. All you have to do is display the text inside each line of the list and let it be selected there. I naturally thought that the unit of selection was a row in a list.
Around this time, I feel like I'm stuck in mobile application development. (I basically live in iOS and Android native app development)
After selecting, you need an action that triggers stage / unstage. If you look at SourceTree, you'll see a button and a right-click menu. Right-clicking is a hassle to use regularly. It is also troublesome to think about the position and shape of the button.
That's why I decided to click the header part of the diff.
hunk
It is easier to display the data obtained from git diff
as it is, so let's display it in hunk units.
The diff header here has multiple lines for each file,
From the line starting with diff --git
to just before the header line of hunk.
The hunk header here is one line starting with @@
.
<diff-per-file>
<diff-header />
<hunk>
<hunk-header />
<hunk-body />
</hunk>
<hunk>
<hunk-header />
<hunk-body />
</hunk>
</diff-per-file>
<!--There may be no hunk such as images-->
<diff-per-file>
<diff-header />
</diff-per-file>
The git diff has the above structure,
For that reason, it displays the diff header with each hunk.
<diff-per-file>
<diff-header />
<hunk>
<hunk-header />
<hunk-body />
</hunk>
<diff-header />
<hunk>
<hunk-header />
<hunk-body />
</hunk>
</diff-per-file>
<diff-per-file>
<diff-header />
<hunk>
<hunk-header dummy="new file" />
<hunk-body img="icon.png " />
</hunk>
</diff-per-file>
If you combine multiple hunks of the same diff, the diff headers will be duplicated,
There seems to be no problem even if they are output to the patch all at once.
(However, I basically only do git apply
on a hunk basis, so there may be hidden issues)
Therefore, multiple lines of text are displayed on one line of the list.
JLabel etc. can put html (like?) Together with <html>
</ html>
.
Collector<CharSequence, ?, String> toHtml = Collectors.joining(
"</nobr><br><nobr>",
"<html><nobr>",
"</nobr></html>");
Arrays.stream(String of the header part.split("\n")).collect(toHtml)
I'm wondering if <nobr> </ nobr>
can be used in any environment now or in the future, but it's useful.
The output of git diff
is as it is.
It is easy to understand if the colors are different for the add line, delete line, and context line.
When adding or deleting images (such as binary files), it is handled in file units, so
The unit hunk doesn't exist and doesn't appear in the output of git diff
.
However, I want to display the image because it is a big deal. In the previous issue, we mentioned the method and precautions.
When displaying in a list
git diff
With that in mind, there are two display methods.
I'm not happy to wait, so let's display what can be displayed first.
(I didn't think it would be a hassle to implement, so I chose the latter as a matter of course, but I think it's totally ant to wait because it depends on the performance of the local machine, not via the network.)
However, JList does not seem to be able to update row by row. So we use JTable with only one column.
As a result of various trials, I divided it into a line with only text and a line with only images. Updating in the following order gave the desired performance.
The following includes hacks that depend on Swing's internal implementation, so
Depending on the version, the same idea and the same code may not work.
I'm checking javac 1.8.0_144
.
(Do you understand that it is the same as the javac version?)
(By the way, are there any plans to dramatically improve the existing components of Swing in the future?)
When it is necessary to display / update each row in JTable, the TableCellRenderer set for each column is called. TableCellRenderer is an interface.
public interface TableCellRenderer {
Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column);
}
There should be several ways to update each row,
Here we use JTable # setRowHeight (int row, int rowHeight)
.
It is essential to change the height from row to row.
You can find the height of the text by putting the text in JLabel. Create a JLabel and set the height before the TableCellRenderer is called.
The height of each row is updated when the data associated with the table changes. This is a sample code.
//I will put together the setRowHeight of the text row first
preRender = () -> {
//If you don't do one of the following, the maximum number of rows in the table will depend on the number of rows initially displayed.
//Probably rowModel inside JTable= null;I think you need
this.table.setRowHeight(1);
// setRowSorter(null);
// tableChanged(new TableModelEvent(getModel()));
final int size = dataModel.getSize();
for (int i = 0; i < size; i++) {
final ListItem item = dataModel.getElementAt(i);
final ImageHolder imageHolder = item.imageHolder();
//If not an image line
if (imageHolder == null || !imageHolder.hasLoader()) {
//Don't cache because it shouldn't be a big cost
final JLabel label = new JLabel();
this.renderer.render(label, item, false, null);
final int height = label.getPreferredSize().height;
table.setRowHeight(i, height);
}
}
};
I wrote it in the sample code, but as a caveat,
If you don't call, etc., the maximum number of rows in the table will depend on the number of rows initially displayed.
If you initially display 3 rows, the table can only display 3 rows.
I'm not sure why this happens, but
Initializing the JTable private SizeSequence rowModel;
seems to behave as expected.
Do not call JTable # setRowHeight (int row, int rowHeight)
more than once for the same row,
It may be that.
As with the text, you can start in advance, I didn't feel any performance problems, so Use TableCellRenderer # getTableCellRendererComponent.
In any case, TableCellRenderer # getTableCellRendererComponent will be called at least when updating the surrounding rows, so It must be implemented so that the image acquisition and the callback call after acquisition are made only once.
Since the display cannot be changed outside of TableCellRenderer # getTableCellRendererComponent,
After getting the image, give the linked item the image
Call JTable # setRowHeight (int row, int rowHeight)
.
Then TableCellRenderer # getTableCellRendererComponent will be called again.
final TableColumn tableColumn = this.table.getColumnModel().getColumn(0);
tableColumn.setCellRenderer((table, value, isSelected, hasFocus, row, column) -> {
final ListItem item = (ListItem) value;
final JLabel label = new JLabel();
//Start image acquisition here or set an image
this.renderer.render(label, item, isSelected, imageIcon -> {
//After image acquisition
final int iconHeight = imageIcon.getIconHeight();
table.setRowHeight(row, iconHeight);
});
return label;
});
It's a progress gif that is familiar every time and has nothing to do with posting.
There are still bugs and issues, but you can commit. I want to be able to display the history soon.
Once you start writing
I was getting tired for some reason, so I decided to move on to the next issue.
I started writing this series and apps It was because I retired and enjoyed being unemployed.
I didn't intend to work for a while yet, Work came down from the sky, so I became a freelancer. It was a flow that I became a programmer, so I think it will continue as it is.
The latest is the renovation of the iOS app.
I haven't written any code yet, but you should git commit
in your own application.
(I haven't run it on a mac yet, but I believe in the JVM)
If you have work at hand, you will be more motivated to make tools outside of work.
Swing
There is no particular reason to write in Swing, There was only "I don't want to write CSS", I intended to implement it temporarily for design, There are no particular problems, so I plan to continue as it is.
I wonder what kind of shape should be used for distribution.
Recommended Posts