Revision 2722

View differences:

org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/requests/LogRequestHelper.java
22 22

  
23 23
package org.gvsig.vcsgis.lib.requests;
24 24

  
25
import java.sql.Timestamp;
26 25
import org.apache.commons.lang3.Range;
27 26
import org.gvsig.tools.dispose.DisposableIterable;
28 27
import org.gvsig.tools.dispose.DisposeUtils;
29
import org.gvsig.vcsgis.lib.VCSGisEntity;
30 28
import org.gvsig.vcsgis.lib.VCSGisEntityEditable;
31 29
import org.gvsig.vcsgis.lib.VCSGisRevision;
32 30
import org.gvsig.vcsgis.lib.repository.VCSGisRepository;
......
43 41
    // in
44 42
    public String entityName;
45 43
    public Range<Integer> number;
46
    public Range<Timestamp> efectiveDate;
47
    public Range<Timestamp> operationDate;
44
//    public Range<Timestamp> efectiveDate;
45
//    public Range<Timestamp> operationDate;
46
    private int maxRevisions;
47
    private int operation;
48
    private Range<Long> excludeRevisionsRange;
48 49
    
49 50
    // out
50 51
    public VCSGisEntityEditable entity;
51 52
    public DisposableIterable<VCSGisRevision> revisions;
53
    private Range<Long> revisionsRange;
52 54

  
53 55
    public LogRequestHelper(VCSGisRepository repository, String entityName) {
54 56
        super(repository, REQUEST_NAME);
55 57
        this.entityName = entityName;
56 58
        this.number = null;
57
        this.efectiveDate = null;
58
        this.operationDate = null;
59
//        this.efectiveDate = null;
60
//        this.operationDate = null;
59 61
        
60 62
        this.entity = null;
61 63
        this.revisions = null;        
......
67 69
        DisposeUtils.disposeQuietly(this.revisions);
68 70
        this.entityName = null;
69 71
        this.number = null;
70
        this.efectiveDate = null;
71
        this.operationDate = null;
72
//        this.efectiveDate = null;
73
//        this.operationDate = null;
72 74
        
73 75
        this.entity = null;
74 76
        this.revisions = null;
......
89 91

  
90 92
    @Override
91 93
    public Range<Long> getExcludeRevisionsRange() {
92
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
94
        return this.excludeRevisionsRange;
93 95
    }
94 96

  
95 97
    @Override
96 98
    public void setExcludeRevisionsRange(Range<Long> excludeRevisionsRange) {
97
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
99
        this.excludeRevisionsRange = excludeRevisionsRange;
98 100
    }
99 101

  
100 102
    @Override
101 103
    public int getOperation() {
102
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
104
        return this.operation;
103 105
    }
104 106

  
105 107
    @Override
106 108
    public void setOperation(int operation) {
107
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
109
        this.operation = operation;
108 110
    }
109 111

  
110 112
    @Override
111 113
    public int getMaxRevisions() {
112
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
114
        return this.maxRevisions;
113 115
    }
114 116

  
115 117
    @Override
116 118
    public void setMaxRevisions(int maxRevisions) {
117
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
119
        this.maxRevisions = maxRevisions;
118 120
    }
119 121

  
120 122
    @Override
121 123
    public Range<Long> getRevisionsRange() {
122
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
124
        return this.revisionsRange;
123 125
    }
124 126

  
125 127
    @Override
126 128
    public void setRevisionsRange(Range<Long> revisionsRange) {
127
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
129
        this.revisionsRange = revisionsRange;
128 130
    }
129 131

  
130 132
}
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/workspace/VCSGisWorkspaceDescriptorImpl.java
24 24

  
25 25
import org.gvsig.fmap.dal.DALLocator;
26 26
import org.gvsig.fmap.dal.DataManager;
27
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
28
import org.gvsig.vcsgis.lib.workspace.VCSGisWorkspaceDescriptor;
29 27
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
30 28
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
31 29
import org.gvsig.tools.ToolsLocator;
......
34 32
import org.gvsig.tools.persistence.PersistentState;
35 33
import org.gvsig.tools.persistence.exception.PersistenceException;
36 34
import org.gvsig.vcsgis.lib.VCSGisLocator;
37
import org.gvsig.vcsgis.lib.workspace.VCSGisWorkspace;
38 35
import org.gvsig.vcsgis.lib.VCSGisManager;
39 36

  
40 37
/**
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/workspace/VCSGisWorkspaceImpl.java
13 13
import java.util.Map;
14 14
import java.util.Set;
15 15
import javax.json.JsonObject;
16
import org.apache.commons.lang3.Range;
16 17
import org.apache.commons.lang3.StringUtils;
17 18
import org.gvsig.expressionevaluator.ExpressionBuilder;
18 19
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
......
43 44
import org.gvsig.tools.logger.FilteredLogger;
44 45
import org.gvsig.tools.task.SimpleTaskStatus;
45 46
import org.gvsig.tools.util.ContainerUtils;
47
import org.gvsig.tools.util.GetItemWithSizeAndIterator64;
46 48
import org.gvsig.tools.util.HasAFile;
47 49
import org.gvsig.vcsgis.lib.DisposableIterableAdapter;
48 50
import org.gvsig.vcsgis.lib.VCSGisChange;
......
149 151

  
150 152
        VarsTable varsTable = new VarsTable();
151 153
        this.code = varsTable.get(this, "WORKSPACE_CODE");
152
        this.label = varsTable.get(this, "WORKSPACE_LABEL");
154
        if (this.code == null) {
155
            throw new RuntimeException("Can't retrieve code from workspace '" + this.getMessageLabel() + "'");
156
        }
153 157
        this.repository = (VCSGisRepository) Json.toObject(varsTable.get(this, "REPOSITORY"));
154 158
        if (this.repository == null) {
155 159
            throw new RuntimeException("Can't retrieve repository from workspace '" + this.getMessageLabel() + "'");
156 160
        }
161
        this.label = varsTable.get(this, "WORKSPACE_LABEL");
157 162
//        LOGGER.debug("===: CREATE WORKSPACE "+ hexId(this)+ " (open code='"+this.code+"', label='"+this.label+"')");
158 163
    }
159 164
    
......
436 441
            return store;
437 442
        } catch (Exception ex) {
438 443
            String msg = "can't open store from '" + this.getMessageLabel() + "'.";
439
            LOGGER.warn(msg, ex);
440 444
            throw new RuntimeException(msg, ex);
441 445
        }
442 446
    }
......
463 467
            return store;
464 468
        } catch (Exception ex) {
465 469
            String msg = "can't open store from '" + this.getMessageLabel() + "'.";
466
            LOGGER.warn(msg, ex);
467 470
            throw new RuntimeException(msg, ex);
468 471
        }
469 472
    }
......
1527 1530
            reloadRepositoryEntities(status);
1528 1531

  
1529 1532
            //TODO calcular las revisiones que tengo para excluirlas
1533
            EntityRow lentity = this.getWorkspaceEntityByName(tableName);
1534
            if(lentity == null){
1535
                status.message("Can't find table '"+tableName+"'");
1536
                status.abort();
1537
                return ERR_ENTITY_NOT_EXISTS;
1538
            }
1539
            
1540
            
1541
            LocalRevisionsTable localRevisionsTable = new LocalRevisionsTable();
1542
            GetItemWithSizeAndIterator64<Feature> lrevisions = localRevisionsTable.getAllRevisions(this, lentity.getEntityCode());
1543
            //Asumimos que lrevisions est? ordenado ascendentemente por numero de revision
1544
//            Long prevRevNumber = null;
1545
            Long minRevision = null;
1546
            Long maxRevision = null;
1547
            for (Feature lrevision : lrevisions) {
1548
                LocalRevisionRow x = new LocalRevisionRow(this, lrevision);
1549
                Long revNumber = x.getNumber();
1550
                //Asumimos que las revisiones que tenemos son consecutivas
1551
//                if(prevRevNumber != null && revNumber != prevRevNumber+1){ //Salto
1552
                    //Borrar la tabla completamente ???
1553
//                    target = this.getFeatureStore(LocalRevisionsTable.TABLE_NAME);
1554
//                    target.edit(MODE_PASS_THROUGH);
1555
//                    target.delete
1556
//                }
1557
                if(minRevision == null){
1558
                    minRevision = revNumber;
1559
                }
1560
                maxRevision = revNumber;
1561
            }
1562
            
1530 1563
            status.message("Executing log request");
1531 1564
            request = this.repository.createLogRequest(tableName);
1565
            if(minRevision != null && maxRevision != null){
1566
                request.setExcludeRevisionsRange(Range.between(minRevision, maxRevision));
1567
            }
1568
            request.setOperation(operation);
1569
            request.setMaxRevisions(maxRevisions);
1570
            
1532 1571
            if( request.execute()!=ERR_OK ) {
1533 1572
                status.message("Can't retriev history of "+tableName+" (error "+request.getLastErrorCode()+")");
1534 1573
                status.abort();
......
1536 1575
            }
1537 1576

  
1538 1577
            status.message("Deleting previous local revision information");
1539
            //TODO: OJO CON EL SALTO
1540

  
1541 1578
            errcode = ERR_CANT_OPEN_STORE;
1542 1579
            target = this.getFeatureStore(LocalRevisionsTable.TABLE_NAME);
1543 1580
            errcode = ERR_CANT_RETRIEVE_SOURCE_FEATURES;
......
1548 1585
            status.setCurValue(0);
1549 1586
            
1550 1587
            errcode = ERR_CANT_INSERT_FEATURES;
1551
            target.edit(FeatureStore.MODE_APPEND);
1588
            target.edit(FeatureStore.MODE_PASS_THROUGH);
1552 1589
            for (VCSGisRevision revision : revisions) {
1590
                if(operation == VCSGisLogRequest.LOG_OP_LAST && revision.getNumber()!=maxRevision+1){
1591
                    //Borrar todo el target ???
1592
                }
1553 1593
                EditableFeature f = target.createNewFeature();
1554 1594
                LocalRevisionRow row = new LocalRevisionRow(this, f);
1555 1595
                row.copyFrom(revision);
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/workspace/tables/VarsTable.java
65 65
            }
66 66
            return f.getString(VAR_VALUE);
67 67
        } catch (Exception ex) {
68
            LOGGER.warn("Can't retrieve value for '" + name + "'.", ex);
69 68
            return null;
70 69
        } finally {
71 70
            DisposeUtils.disposeQuietly(store);
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/workspace/tables/LocalRevisionsTable.java
201 201
        try {
202 202
            store = workspace.getFeatureStore(TABLE_NAME);
203 203
            if( StringUtils.isBlank(entityCode) ) {
204
                GetItemWithSizeAndIterator64<Feature> revsions = store.getFeatures64(
204
                GetItemWithSizeAndIterator64<Feature> revisions = store.getFeatures64(
205 205
                        null, 
206 206
                        "\""+COD_ENTITY+"\",\""+REVISION_NUMBER+"\"", 
207 207
                        true);
208
                return revsions;
208
                return revisions;
209 209
            }
210
            GetItemWithSizeAndIterator64<Feature> revsions = store.getFeatures64(
210
            GetItemWithSizeAndIterator64<Feature> revisions = store.getFeatures64(
211 211
                    ""+COD_ENTITY+"='"+entityCode+"'",
212 212
                    "\""+REVISION_NUMBER+"\"", 
213 213
                    true
214 214
            );
215
            return revsions;
215
            return revisions;
216 216
        } catch (Exception ex) {
217 217
            throw new RuntimeException("Can't retrieve changes by entity.", ex);
218 218
        } finally {
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/repository/localdb/tables/HooksRepoTable.java
46 46
                .setSize(40)
47 47
                .setIsPrimaryKey(true)
48 48
                .setLabel("Code")
49
                .setReadOnly(true);
49
                .setReadOnly(false)
50
                .setDefaultFieldValue("<%=replace(UUID(),'-','')%>");
50 51
        ft.add(HOOK_OPERATION, DataTypes.STRING)
51 52
                .setSize(50)
52 53
                .setLabel("Operation");
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/repository/localdb/tables/RevisionsRepoTable.java
1 1
package org.gvsig.vcsgis.lib.repository.localdb.tables;
2 2

  
3 3
import java.sql.Timestamp;
4
import org.apache.commons.lang3.Range;
4 5
import org.gvsig.fmap.dal.DALLocator;
5 6
import org.gvsig.fmap.dal.DataManager;
6 7
import org.gvsig.fmap.dal.feature.EditableFeatureType;
......
11 12
import org.gvsig.tools.dataTypes.DataTypes;
12 13
import org.gvsig.tools.dispose.DisposableIterable;
13 14
import org.gvsig.tools.dispose.DisposeUtils;
15
import org.gvsig.vcsgis.lib.VCSGisRevision;
16
import org.gvsig.vcsgis.lib.repository.VCSGisRepositoryRevision;
14 17
import org.gvsig.vcsgis.lib.repository.localdb.VCSGisRepositoryLocaldb;
15
import org.gvsig.vcsgis.lib.repository.VCSGisRepositoryRevision;
16
import org.gvsig.vcsgis.lib.VCSGisRevision;
18
import static org.gvsig.vcsgis.lib.repository.requests.VCSGisLogRequest.LOG_OP_PREVIOUS;
17 19

  
18 20
/**
19 21
 *
......
258 260
            }
259 261
        }
260 262
    }
263
    
264
    public DisposableIterable<Feature> getRevisionsByRange(VCSGisRepositoryLocaldb repository, String entityCode, int operation, int limit, Range<Long> excludeRevisionsRange ) {
261 265

  
266
        FeatureStore store = null;
267
        DisposableIterable<Feature> features = null;
268
        try {
269
            
270
            Long revNumber = excludeRevisionsRange.getMaximum();
271
            String operator =">";
272
            if (operation == LOG_OP_PREVIOUS) {
273
                operator = "<";
274
                revNumber = excludeRevisionsRange.getMinimum();
275
            }
276
            
277
            String sql = String.format(
278
                    "select * \n" +
279
                    "from \"%s\"\n" +
280
                    "where \n" +
281
                    "  \"COD_ENTITY\" = '%s' \n" +
282
                    "  and \"%s\" %s %d \n" +
283
                    "order by \"%s\" asc" +
284
                    "limit %d",
285
                    TABLE_NAME,
286
                    entityCode,
287
                    REVISION_NUMBER,
288
                    operator,
289
                    revNumber,
290
                    REVISION_NUMBER,
291
                    limit
292
            );
293

  
294
            store = repository.openFeatureStore(TABLE_NAME, sql);
295
            
296
            FeatureSet fset = store.getFeatureSet();
297
            features = fset.iterable();
298
            return features;
299
            
300
//            FeatureSet fset = null;
301
//            StringBuilder builder = new StringBuilder("\""+COD_ENTITY+"\"='"+entityCode+"'");
302
//            if (operation == LOG_OP_PREVIOUS) {
303
//                builder.append(" AND \""+REVISION_NUMBER+"\"<"+excludeRevisionsRange.getMinimum());
304
//            } else if (operation == LOG_OP_LAST) {
305
//                builder.append(" AND \""+REVISION_NUMBER+"\">"+excludeRevisionsRange.getMaximum());
306
//            }
307
//            
308
//            FeatureQuery query = store.createFeatureQuery();
309
//            query.setFilter(builder.toString());
310
//            query.setLimit(limit);
311
//            FeatureQueryOrder order = store.;
312
//            query.setOrder(order);
313
//            fset = store.getFeatureSet(query);
314
//            features = fset.iterable();
315
//            return features;
316
        } catch (Exception ex) {
317
            DisposeUtils.disposeQuietly(features);
318
            throw new RuntimeException("Can't retrieve revisions of 'ENTITY["+entityCode+"].", ex);
319
        } finally {
320
            if( store!=null ) {
321
                DisposeUtils.dispose(store);
322
            }
323
        }
324
    }
262 325
    
326
    
327

  
328
    
263 329
}
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.impl/src/main/java/org/gvsig/vcsgis/lib/repository/localdb/requests/LogRequestLocaldb.java
21 21
 */
22 22
package org.gvsig.vcsgis.lib.repository.localdb.requests;
23 23

  
24
import java.sql.Timestamp;
25 24
import java.util.Iterator;
26 25
import org.apache.commons.lang3.Range;
27 26
import org.gvsig.fmap.dal.feature.Feature;
28 27
import org.gvsig.tools.dispose.DisposableIterable;
29 28
import org.gvsig.vcsgis.lib.EntityEditableImpl;
30
import org.gvsig.vcsgis.lib.VCSGisEntity;
31 29
import static org.gvsig.vcsgis.lib.VCSGisManager.ERR_ENTITY_NOT_EXISTS;
32 30
import static org.gvsig.vcsgis.lib.VCSGisManager.ERR_OK;
33 31
import org.gvsig.vcsgis.lib.VCSGisRevision;
34
import org.gvsig.vcsgis.lib.repository.requests.VCSGisLogRequest;
35 32
import org.gvsig.vcsgis.lib.repository.localdb.VCSGisRepositoryLocaldb;
36 33
import org.gvsig.vcsgis.lib.repository.localdb.tables.EntitiesRepoTable;
37 34
import org.gvsig.vcsgis.lib.repository.localdb.tables.EntitiesRepoTable.EntityRepoRow;
38 35
import org.gvsig.vcsgis.lib.repository.localdb.tables.RevisionsRepoTable;
39 36
import org.gvsig.vcsgis.lib.repository.localdb.tables.RevisionsRepoTable.RevisionRepoRow;
40
import org.gvsig.vcsgis.lib.repository.VCSGisRepositoryRevision;
37
import org.gvsig.vcsgis.lib.repository.requests.VCSGisLogRequest;
41 38
import org.gvsig.vcsgis.lib.requests.LogRequestHelper;
42 39

  
43 40
/**
......
103 100
                    @Override
104 101
                    public VCSGisRevision next() {
105 102
                        Feature f = itFeatures.next();
106
                        return new RevisionRepoRow(getRepository(), f);
103
                        VCSGisRevision rev = new RevisionRepoRow(getRepository(), f);
104
                        return rev;
107 105
                    }
108 106
                };
109 107
                return it;
......
115 113
            }
116 114
        };
117 115
        helper().revisions = result;
118
        //helper().revisionsRange = ... //FIXME: Calcular
116
        
117
        Long minRevision = Long.MAX_VALUE;
118
        Long maxRevision = -1L;
119
        for (VCSGisRevision revision : result) {
120
            minRevision = revision.getNumber()<minRevision?revision.getNumber():minRevision;
121
            maxRevision = revision.getNumber()>maxRevision?revision.getNumber():maxRevision;
122
        }
123
        helper().setRevisionsRange(Range.between(minRevision, maxRevision));
119 124
        return error(ERR_OK);
120 125
    }
121 126

  
122 127
    @Override
123 128
    public Range<Long> getExcludeRevisionsRange() {
124
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
129
        return this.helper().getExcludeRevisionsRange();
125 130
    }
126 131

  
127 132
    @Override
128 133
    public void setExcludeRevisionsRange(Range<Long> excludeRevisionsRange) {
129
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
134
        this.helper().setExcludeRevisionsRange(excludeRevisionsRange);
130 135
    }
131 136

  
132 137
    @Override
133 138
    public int getOperation() {
134
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
139
        return this.helper().getOperation();
135 140
    }
136 141

  
137 142
    @Override
138 143
    public void setOperation(int operation) {
139
//        helper().setOperation(operation);
140
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
144
        this.helper().setOperation(operation);
141 145
    }
142 146

  
143 147
    @Override
144 148
    public int getMaxRevisions() {
145
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
149
        return this.helper().getMaxRevisions();
146 150
    }
147 151

  
148 152
    @Override
149 153
    public void setMaxRevisions(int maxRevisions) {
150
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
154
        this.helper().setMaxRevisions(maxRevisions);
151 155
    }
152 156

  
153 157
    @Override
154 158
    public Range<Long> getRevisionsRange() {
155
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
159
        return this.helper().getRevisionsRange();
156 160
    }
157 161

  
158 162
    @Override
159 163
    public void setRevisionsRange(Range<Long> revisionsRange) {
160
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
164
        this.helper().setRevisionsRange(revisionsRange);
161 165
    }
162 166
}
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.lib/org.gvsig.vcsgis.lib.api/src/main/java/org/gvsig/vcsgis/lib/repository/requests/VCSGisLogRequest.java
31 31
 * @author jjdelcerro
32 32
 */
33 33
public interface VCSGisLogRequest extends VCSGisRequest {
34

  
34
    
35
    public final static int LOG_OP_LAST = 0;
36
    public final static int LOG_OP_PREVIOUS = 1;
37
    
35 38
    // in
36 39
    public String getEntityName();
37 40
    
org.gvsig.vcsgis/trunk/org.gvsig.vcsgis/org.gvsig.vcsgis.swing/org.gvsig.vcsgis.swing.impl/src/main/java/org/gvsig/vcsgis/swing/impl/changes/LocalChangesController.java
328 328
        btnLocalUnCheckAll.setEnabled(changes!=null && changes.size64()>0);
329 329
        btnLocalRefresh.setEnabled(changes!=null);
330 330
        btnLocalRevert.setEnabled(false);      
331
        btnLocalRevert.setVisible(false);      
331 332
        btnLocalCommit.setEnabled(changes!=null && !this.changes.isSelectionEmpty());
332 333
        //Show form
333 334
        int row = this.tblLocalChanges.getSelectedRow();

Also available in: Unified diff