home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Symantec Visual Cafe for Java 2.5
/
symantec-visual-cafe-2.5-database-dev-edition.iso
/
VCafe
/
prosrc.bin
/
DbaDataStore.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1998-03-18
|
35.8 KB
|
1,203 lines
/*
* DbaDataStore.java 1.0 12 Jan 1997
*
* Copyright (c) 1996 Krumel & Associates, Inc. All Rights Reserved.
*
* This software is provided as is. Krumel & Associates shall not be liable
* for any damages suffered by licensee as a result of using, modifying or
* distributing this software or its derivatives.
*/
package symantec.itools.db.awt;
import symantec.itools.db.pro.*;
import java.sql.SQLException;
import java.util.BitSet;
import java.util.StringTokenizer;
import java.sql.Types;
/**
* This implements data store for the TableView component that uses a dbANYWHERE
* server for its data.
* <p>
* All rows coming from DbaDataSource are zero-relative.<br>
* All columns coming from DbaDataSource are one-relative.
*
* @see symantec.itools.db.awt.DbDataSource
* @see symantec.itools.db.awt.DbDataUpdater
* @see symantec.itools.db.awt.MetaTable
*/
public class DbaDataStore implements DbDataStore, MetaTable, DbDataUpdater {
Position position;
RelationView master;
RelationView relView;
MultiView multiView;
DbDataSource source = null;
DbaDataLink link;
int coltoshow=0;
RelationViewMetaData meta;
/**
* Obsolete.
*/
public static final int MAX_DISPLAY_SIZE = 60;
/**
* Constructs a DbaDataStore that uses the given RelationView for data.
*
* @param rv the RelatioView to used for data access
* @param masterView obsolete
* @exception SQLException
* if a SQL database access error occurred
*/
public DbaDataStore(RelationView rv, RelationView masterView) throws SQLException {
if (masterView != null)
{
master = masterView;
}
relView = rv;
multiView = rv.getMultiView();
meta = relView.getMetaData();
position = new Position(rv);
}
/**
* Clears all row data from this DbaDataStore.
* <p>
* Note that setDbDataSource() must be called before using this method.
*
* @exception SQLException
* if a SQL database access error occurred
*
* @see #setDbDataSource
*/
void resetRows() throws SQLException
{
int count;
// // synchronized(position)
{
count = position.getIgnoreCount();
}
if (count > 0)
{
return;
}
initRowMapping();
source.view.clear();
// source.view.redrawAsync(); // clear calls redrawAsync
}
/**
* This method is called when the current Record in the RelationView is changed.
* <p>
* Note that setDbDataSource() must be called before using this method.
*
* @exception SQLException
* if a SQL database access error occurred
*
* @see #setDbDataSource
*/
void notifyRecordChange() throws SQLException
{
int count;
// synchronized(position)
{
count = position.getIgnoreCount();
}
if (count > 0)
{
return;
}
int row;
// synchronized(position)
{
row = position.get();
}
//vj
//if (relView.getCurrentRecordState() == Record.RECSTATE_NEW)
//{
source.view.scrollUpDownAbsolute(row -1);
//}
//source.view.setFocusToRow(row);
}
/**
* Sets the fetch mode for getting data. When fetch mode is enabled,
* a grid expects to rapidly read lots of data for read only purposes.
* Knowing this can allow some data stores to more efficiently get the
* data. The TableView provides a guarantee that the current data row will
* not be changed
* @param manual true if fetch mode is to be entered
*/
public void fetchMode(boolean manual)
{
setManRowChangeFlag(manual);
}
/**
* Returns the current send notification flag.
* This is used to determine if the RelationView sends notifications
* when it's modified.
* When fetch mode is enabled this returns a value of true.
*
* @return the current send notification flag
* @see #fetchMode
*/
public boolean manualRowChangeFlag()
{
// synchronized (position)
{
return position.getNotificationMode();
}
}
private void setManRowChangeFlag(boolean val)
{
try
{
// synchronized (position)
{
position.setNotificationMode(val);
}
}
catch(SQLException ex) {}
}
/**
* Sets the current row in the data store.
* <p>
* This is a standard DbDataStore interface method.
*
* @param row the zero-relative row index
* @exception TypeNotSupported
* if the data store does not support the type of action requested
* or is not successful
*/
public void setCurrentRow(int row) throws TypeNotSupported {
row++;
try
{
int translatedRow = translateRow(row);
// synchronized (position)
{
position.set(translatedRow);
}
} catch(Exception ex)
{
throw new TypeNotSupported(ex.getMessage());
}
}
/**
* Determines if the given row is the current row in the data store.
*
* @param row the zero-relative index of the row to check
* @return true if it is the current row, false otherwise
* @see #setCurrentRow
*/
public boolean isCurrentRow(int row) {
try
{
int translatedRow = translateRow(row);
// synchronized (position)
{
return translatedRow == position.get();
}
}
catch(Exception ex)
{
return false;
}
}
/**
* Sets the database data source that requests data and possibly
* caches the SQL data.
* <p>
* This is a standard DbDataStore interface method.
*
* @param ds the data source
*/
public void setDbDataSource(DbDataSource ds) {
if (source != null)
{
return;
}
source = ds;
initRowMapping();
link = new DbaDataLink(this);
// synchronized(position)
{
position.ignoreNotification(true);
}
try
{
relView.bindRecordSet(link);
relView.bindCurrentRecord(link);
} catch(SQLException ex) { /*this should never happend*/ }
// synchronized(position)
{
position.ignoreNotification(false);
}
}
/**
* Called by a DbDataSource to determine if the store provides its own
* caching services.
* <p>
* This is a standard DbDataStore interface method.
*
* @return true if the store provides scrollable caching
*/
public boolean supportsCaching() {
return true;
}
/**
* Gets the last row that exists within the specified range.
* <p>
* This is a standard DbDataStore interface method.
*
* @param top the zero-relative index of the first row in the range
* @param bottom the zero-relative index of the last row in the range
* @return the last row that exists in the given range
* @exception DataNotAvailable
* if the requested data cannot be accessed in the data store
*/
public int validDataRowRange(int top, int bottom) throws DataNotAvailable {
//iterate from top to bottom and find the last valid number in range
//adjust for row indices being zero relative
top++;
bottom += 2; //a few extra for scrollbars
int lastInRange = Math.max(1, top); //always want to ensure at least try
//first row
try {
setManRowChangeFlag(true);
while(lastInRange<=bottom) {
translateRow(lastInRange);
lastInRange++;
}
} catch(DataNotAvailable ex) {
} finally {
setManRowChangeFlag(false);
}
if (lastInRange == top) {
throw new DataNotAvailable("top is greater than last row in database");
}
return lastInRange-1;
}
/**
* Gets the data element for the specified position.
* <p>
* This is a standard DbDataStore interface method.
*
* @param row the zero-relative index of the element's row
* @param col the one-relative index of the element's column
* @return the element's data
* @exception DataNotAvailable
* if the requested data cannot be accessed in the data store
*/
public Data getData(int row, int col) throws DataNotAvailable {
//adjust for row indices being 0 relative
row++;
Data d = null;
try {
setManRowChangeFlag(true);
int translatedRow = translateRow(row);
boolean success;
// synchronized(position)
{
success = position.set(translatedRow);
}
if (!success) {
throw new DataNotAvailable("Could not move to row " + row);
}
String str = relView.getStringValue(col);
if (str == null) { str = ""; }
d = new ImageStringData(source, str);
} catch(Exception ex) {
throw new DataNotAvailable(ex.getMessage());
} finally {
setManRowChangeFlag(false);
}
return d;
}
/**
* Sets a new value in the specified position. The method is only
* called when the store supports caching.
* <p>
* This is a standard DbDataStore interface method.
*
* @param row the zero-relative index of the row to update
* @param col the one-relative index of the column to update
* @param data the data element that holds the new value
* @exception TypeNotSupported
* if the data store does not support the type of action requested
* or is not successful
*/
public void update(int row, int col, Data data) throws TypeNotSupported {
//adjust for row indices being 0 relative
row++;
try {
setManRowChangeFlag(true);
int translatedRow = translateRow(row);
// synchronized(position)
{
position.set(translatedRow);
// position.ignoreNotification(true);
}
//assume only string support for now
relView.setValueFromString(col, data.toString());
// synchronized(position)
{
// position.ignoreNotification(false);
}
} catch(Exception ex) {
throw new TypeNotSupported(ex.getMessage());
} finally {
setManRowChangeFlag(false);
}
}
//BS: added NONEXISTS_ROW support
/**
* Gets the current state of the specified row.
*
* @param row the zero-relative row index
* @return the state of the row's data. One of NEW_ROW, CLEAN_ROW, DELETED_ROW,
* or MODIFIED_ROW or NONEXISTS_ROW
* @see symantec.itools.db.awt.DataSource#NEW_ROW
* @see symantec.itools.db.awt.DataSource#CLEAN_ROW
* @see symantec.itools.db.awt.DataSource#DELETED_ROW
* @see symantec.itools.db.awt.DataSource#MODIFIED_ROW
* @see symantec.itools.db.awt.DataSource#NONEXISTS_ROW
*/
public int rowState(int row)
{
//adjust for row indices being 0 relative
row++;
int rowState = DataSource.NEW_ROW;
try
{
setManRowChangeFlag(true);
int translatedRow = translateRow(row);
// synchronized(position)
{
if(position.set(translatedRow) == false)
rowState = DataSource.NONEXISTS_ROW;
}
if(rowState != DataSource.NONEXISTS_ROW){
byte state = relView.getCurrentRecordState();
switch(state)
{
case Record.RECSTATE_NEW:
rowState = DataSource. NEW_ROW; break;
case Record.RECSTATE_DELETED:
rowState = DataSource. DELETED_ROW; break;
case Record.RECSTATE_MODIFIED:
rowState = DataSource. MODIFIED_ROW; break;
case Record.RECSTATE_EXISTING:
rowState = DataSource. CLEAN_ROW; break;
default:
//now what?!?
}
}
}
catch(Exception ex)
{
//if fails assume new
//vj:
//ex.printStackTrace();
//System.out.println(ex.toString());
}
finally
{
setManRowChangeFlag(false);
}
return rowState;
}
/**
* Requests the data store clear all cached data.
* <p>
* This is a standard DbDataStore interface method.
*
*/
public void clear() {
initRowMapping(); //time to start all over
}
/**
* Requests the data store get the values from the database again.
* <p>
* This is a standard DbDataStore interface method.
*
*/
public void refresh() {
lastIndex_=0;
lastRowRetrieved = 0;
try {
relView.restartMultiView();
} catch(SQLException ex) {
}
}
/**
* Requests that any actions performed on a row be undone. The meaning
* is left open and is interpreted as appropriate for the type of
* data store.
* <p>
* This is a standard DbDataStore interface method.
*
* @param row the zero-relative row index
* @exception TypeNotSupported
* if the data store does not support the type of action requested
* or is not successful
*/
public void undoRow(int row) throws TypeNotSupported {
row++;
try {
// synchronized(position)
{
position.ignoreNotification(true);
}
relView.undoRecord();
} catch(SQLException ex) {
throw new TypeNotSupported(ex.getMessage());
} finally {
// synchronized(position)
{
position.ignoreNotification(false);
}
}
}
/**
* Returns the number of rows actually retrieved from the database.
* <p>
* This is a standard DbDataStore interface method.
*
*/
public int rowsRetrieved() {
return lastIndex_;
}
/**
* Requests the store to get all of the elements in the result set.
* <p>
* This is a standard DbDataStore interface method.
*
* @return the number of rows gotten
*/
public int fetchAllRows() {
int count=1;
try {
setManRowChangeFlag(true);
while(true) {
translateRow(count);
count++;
}
} catch(DataNotAvailable ex) {
} finally {
setManRowChangeFlag(false);
}
return count-1;
}
//-------------------------------------------------------------------------
// DbDataUpdater Methods
//-------------------------------------------------------------------------
/**
* Undeletes a row.
* <p>
* This is a standard DbDataUpdater interface method.
*
* @param row the zero-relative row index
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public void undeleteRow(int row) throws TypeNotSupported {
try {
row++;
//BS: current record in relation view should be set to 'row'
//otherwise the current recorde is always the first
position.set(row);
// synchronized(position)
{
position.ignoreNotification(true);
}
relView.undoRecord();
} catch(SQLException ex) {
throw new TypeNotSupported(ex.getMessage());
} finally {
// synchronized(position)
{
position.ignoreNotification(false);
}
}
}
/**
* Deletes a row or marks a row for deletion.
* <p>
* This is a standard DbDataUpdater interface method.
*
* @param row the zero-relative row index
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public void deleteRow(int row) throws TypeNotSupported {
try {
//adjust for row indices being zero relative
row++;
//BS: current record in relation view should be set to 'row'
//otherwise the current record is always the first and gets
//deleted
position.set(row);
// synchronized(position)
{
position.ignoreNotification(true);
}
relView.deleteRecord();
} catch(SQLException ex) {
throw new TypeNotSupported(ex.getMessage());
} finally {
// synchronized(position)
{
position.ignoreNotification(false);
}
}
}
/**
* Saves the current state as appopriate.
* If this object caches, it iterates through the cache and updates
* all non-clean rows.
* <p>
* This is a standard DbDataUpdater interface method.
*
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public void save() throws TypeNotSupported {
try {
relView.saveMultiView();
} catch(SQLException ex) {
throw new TypeNotSupported(ex.getMessage());
}
}
/**
* Gets the next new Record within the RelationView's Record buffers.
* After calling this method, the current Record of the RelationView will
* be positioned at the new Record.
*
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public void getNewRecord() throws TypeNotSupported
{
try {
relView.getNewRecord();
} catch(SQLException ex) {
throw new TypeNotSupported(ex.getMessage());
}
}
/**
* Appends a new row.
* @param row ignored
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public void insertRow(int row) throws TypeNotSupported {
//vj: fetchAllRows may be inefficient if the table has too many rows
// but exhibits consistent behaviour.
fetchAllRows();
appendRow();
}
/**
* Appends a new row.
* <p>
* This is a standard DbDataUpdater interface method.
*
* @return the zero-relative index of the new row
* @exception TypeNotSupported
* if the data source does not support the type of action requested
* or is not successful
*/
public int appendRow() throws TypeNotSupported {
/*
// synchronized(position)
{
position.ignoreNotification(true);
}
*/
getNewRecord();
/*
// synchronized(position)
{
position.ignoreNotification(true);
}
*/
return 0;
}
String m_InputColumnNames = null;
/**
* Specifies the names of the columns to show.
* @param name column names
*/
public void setColumnsNamesToShow(String name){
m_InputColumnNames = name;
}
//hides or shows columns depending of the DataBinding that was given to the Grid
/**
* Hides or shows columns depending of the Data Binding that was given to the Grid.
*/
public void setColumnsToShow(){
//suppress the part after '%'
StringTokenizer stf = new StringTokenizer(m_InputColumnNames,"%");
StringTokenizer st = null;
if(stf.hasMoreTokens())
st = new StringTokenizer(stf.nextToken(),"@,");
String n = null;
if(st.hasMoreTokens())
n = st.nextToken();
if(st.hasMoreTokens()){
//check if the 1st parameter is 'All', in that case, don't do anything
n = st.nextToken();
if(!n.equalsIgnoreCase("All")){
int count = 0;
try{
count = meta.getColumnCount();
//first hide all columns (easier)
for(int i = 0; i < count; i++)
source.view.showColumn(i+1, false);
boolean goon = true;
do{
//is this a valid column name ?
try{
source.view.showColumn(columnNumberfromName(n), true);//meta index is 0 based
}catch(SQLException e){
//this maybe a column index
source.view.showColumn(Integer.parseInt(n), true);
}
if(st.hasMoreTokens())
n = st.nextToken();
else
goon = false;
}while(goon);
}catch(NumberFormatException ex){
//we got an error there, a parameter is neither a valid
//column index, nor a valid column name. Show all columns
for(int i = 0; i < count; i++)
source.view.showColumn(i+1, true);
}
catch(SQLException ex){
//we got an error there, a parameter is neither a valid
//column index, nor a valid column name. Show all columns
for(int i = 0; i < count; i++)
source.view.showColumn(i+1, true);
}
}
}
}
/**
* Gets the index of the column with the specified name.
* @param n the column name
* @return the column index
* @exception SQLException if the column cannot be found
*/
public int columnNumberfromName(String n) throws SQLException{
int col = 1;
int count = meta.getColumnCount();
while(col <= count){
if(n.equals(meta.getColumnName(col))){
return col;
}
col++;
}
throw new SQLException("column name: " + n + "not found!");
}
//-------------------------------------------------------------------------
// MetaTable Methods
//-------------------------------------------------------------------------
/**
* Sets the number of columns to show.
* @param the number of columns
*/
public void setColtoShow(int val){
coltoshow=val;}
/**
* Configures the given TableView the desired way.
* TableView setup often depends on the number and type of data fields
* that will be displayed.
* <p>
* This is a standard MetaTable interface method.
*
* @param view the grid to configure
*/
//BS: setupTableView changed to setupTableView(TableView v);
//changed name of meth. and param.
//TableView.AUTONUMBER changed to TableView.AUTONUMBER
public void setupTableView(TableView v) {
try {
//create the proper number of columns
//make sure the BasicCell is set as default
v.setAutoRedraw(false);
//int cols = meta.getColumnCount();
int cols = coltoshow;
if(coltoshow==0||meta.getColumnCount()<=coltoshow)
cols=meta.getColumnCount();
v.createColumns(cols);
//setup row headings
v.setRowLabelHeadingStyle(TableView.AUTONUMBER);
//set the column headings and widths
for (int col=1; col<=cols; col++) {
int size = meta.getColumnDisplaySize(col);
size = Math.min(0, size);
size = Math.max(0, MAX_DISPLAY_SIZE);
v.setHeading(meta.getColumnLabel(col),
col,
java.lang.Math.min(size, 10));
setupColumn(v, col);
}
setColumnsToShow();
v.setAutoRedraw(true);
} catch(SQLException ex) {
//Not much to do here but set one heading called error
//and set the message in the first cell
}
}
/**
* Obsolete.
*/
public void setDataSource(DataSource ds) { }
/**
* Determines if the data of the cell at the given location is
* user-editable.
* <p>
* This is a standard MetaTable interface method.
*
* @param row the zero-relative row index
* @param col the one-relative column index
* @return true if it is user-editable, false otherwise
* @exception DataNotAvailable
* if the requested data cannot be accessed in the data store
*/
public boolean isDataEditable(int row, int col) throws DataNotAvailable {
try {
//adjust for row indices being zero relative
row++;
setManRowChangeFlag(true);
int translatedRow = translateRow(row);
boolean success;
// synchronized(position)
{
success = position.set(translatedRow);
}
if (success) {
//System.out.println( col + " " + meta.isWritable(col) + " " + relView.isCurrentRecordWritable());
return meta.isWritable(col) && relView.isCurrentRecordWritable();
}
} catch(SQLException ex) {
throw new DataNotAvailable(ex.getMessage());
} finally {
setManRowChangeFlag(false);
}
//this should never be reached
return true;
}
//BS: added arrangeForViewing, this function newly defined in DataStore interface
/**
* Adjusts the given data as needed before it is viewed in the TableView.
* <p>
* This is a standard MetaTable interface method.
*
* @param the data
* @return the arranged data
*/
public Data[] arrangeForViewing(Data data[]) {
return data;
}
/**
* Sets up the specified column in the given view as needed.
* Column setup often varies depending on the type of data that will
* be shown in the column.
* <p>
* This is a standard MetaTable interface method.
*
* @param view the TableView that is being set up
* @param col the one-relative position of the column to set up
*/
public void setupColumn(TableView view, int col) {
//assume all cols aligned left
try {
int type = meta.getColumnType(col);
switch(type) {
case Types.BIGINT:
case Types.INTEGER:
case Types.DOUBLE:
case Types.FLOAT:
case Types.NUMERIC:
case Types.SMALLINT:
case Types.TINYINT:
case Types.REAL:
view.setColumnAlignment(col,TableView.RIGHT);
break;
case Types.CHAR:
case Types.DATE:
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NULL:
case Types.OTHER:
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
case Types.TIME:
case Types.TIMESTAMP:
case Types.BIT:
default:
view.setColumnAlignment(col,TableView.LEFT);
}
if (meta.isCurrency(col)) {
view.setColumnAlignment(col,TableView.RIGHT);
}
if (!meta.isWritable(col)) {
view.setColEditable(col, false);
}
} catch(SQLException ex) {
//why not try a default
view.setColumnAlignment(col,TableView.LEFT);
}
}
//all map functions work on 1 relative rows!!!
int rowMapping[];
BitSet createdRows;
int lastValidIndex;
int lastIndex_ = 0; //pointer to last element in map,
//waste the first
int lastRowRetrieved = 0; //last row retrieved using position.set()
boolean obtainedAllRows = false;
final static int START_SIZE = 100;
final static int INC_SIZE = 100;
private void initRowMapping() {
rowMapping = new int[START_SIZE];
lastValidIndex = START_SIZE -1;
lastRowRetrieved = 0;
lastIndex_ = 0;
obtainedAllRows = false;
createdRows = new BitSet();
}
void printMap() {
System.out.println("Row mappings - size="+lastValidIndex +
"\n\tlastIndex="+lastIndex_+ " lastRow="+lastRowRetrieved);
for(int i=0;i<=lastIndex_; i++) {
System.out.println("\trow "+i+" -> "+rowMapping[i]);
}
}
private int translateRow(int r) throws DataNotAvailable {
boolean success;
try {
while(lastIndex_ < r) {
//if lastRowRetrieved has already been obtained through
//an insert then increment and keep going
if (createdRows.get(lastRowRetrieved+1)) {
lastRowRetrieved++;
continue;
}
//need to fetch rows up to 'r'
// synchronized(position)
{
success = position.set(lastRowRetrieved+1);
}
if (!success) {
obtainedAllRows = true; //set the flag and boogie out
throw new DataNotAvailable("Ran out of rows to fetch at row=" +
(lastRowRetrieved+1));
} else {
//inc last row and insert into map
lastRowRetrieved = relView.getCurrentRecordNumber();
lastIndex_++;
growMap();
rowMapping[lastIndex_] = lastRowRetrieved;
}
}
return rowMapping[r];
} catch (SQLException e) {
throw new DataNotAvailable(e.getMessage());
}
}
//creates the new record and returns the translated row
//number
private int insertRowIntoMap(int r) throws DataNotAvailable {
int actual;
try {
//make sure already mapped row
translateRow(r);
//create a new record
relView.getNewRecord();
actual = relView.getCurrentRecordNumber();
createdRows.set(actual);
//shift all array indices down one from specified row 'r'
growMap();
int numToCopy = lastIndex_+1-r;
System.arraycopy(rowMapping, r, rowMapping, r+1, numToCopy);
lastIndex_++; //we just added a row but did not retrieve one
rowMapping[r] = actual;
} catch(Exception e) {
throw new DataNotAvailable(e.getMessage());
}
return actual;
}
//new row number of 1 relative
private int appendRowIntoMap() throws DataNotAvailable {
//record should NOT have already been created
//before call, lastRow will be the row number
//appended
//move to end of all records
try {
while(!obtainedAllRows) {
translateRow(lastRowRetrieved + 1);
}
} catch(DataNotAvailable ex) {
if (!obtainedAllRows) {
throw ex;
}
}
//create new record
try {
relView.getNewRecord();
//get number and insert into map
growMap();
lastRowRetrieved = relView.getCurrentRecordNumber();
createdRows.set(lastRowRetrieved);
rowMapping[++lastIndex_] = lastRowRetrieved;
} catch(SQLException ex) {
throw new DataNotAvailable("Could not create new record");
}
return lastIndex_;
}
final void growMap() {
if (lastIndex_ == lastValidIndex-1) { //minus 1 for safety b/c I'm tired
//grow array
int newMap[] = new int[lastValidIndex+=INC_SIZE];
System.arraycopy(rowMapping, 0, newMap, 0, rowMapping.length);
rowMapping = newMap;
}
}
/**
* Obsolete.
*/
public Object getSynchronizationObject()
{
return multiView;
}
}
class Position
{
int frozenRecordNumber = 0;
int notificationMode = 0;
boolean frozen = false;
RelationView relView;
int ignoreCount = 0;
String name = "";
Position (RelationView rv)
{
relView = rv;
try
{
name = rv.getName();
}
catch (SQLException e)
{
}
}
void freeze() throws SQLException
{
frozen = true;
ignoreNotification(true);
frozenRecordNumber = relView.getCurrentRecordNumber();
relView.enableBindingNotify(false, true);
relView.enableDetailSQL(false);
}
void thaw() throws SQLException
{
if (frozenRecordNumber > 0)
{
goTo(frozenRecordNumber);
}
relView.enableDetailSQL(true);
relView.enableBindingNotify(true, true);
frozen = false;
ignoreNotification(false);
}
boolean set(int recordNumber) throws SQLException
{
if (relView.getCurrentRecordNumber() == recordNumber)
{
return true;
}
if (getNotificationMode() && !frozen)
{
freeze();
}
return goTo(recordNumber);
}
boolean goTo(int recordNumber) throws SQLException
{
boolean success = false;
ignoreNotification(true);
success = relView.goTo(recordNumber);
ignoreNotification(false);
return success;
}
int get() throws SQLException
{
if (frozen)
{
return frozenRecordNumber;
}
return relView.getCurrentRecordNumber();
}
void setNotificationMode(boolean mode) throws SQLException
{
if (mode)
{
notificationMode++;
}
else
{
notificationMode--;
if (notificationMode == 0 && frozen)
{
thaw();
}
}
}
boolean getNotificationMode()
{
return notificationMode > 0;
}
void ignoreNotification(boolean flag)
{
if (flag)
{
ignoreCount++;
}
else
{
ignoreCount--;
}
}
int getIgnoreCount()
{
return ignoreCount;
}
}