📄 mtab.java
字号:
/******************************************************************************
* The contents of this file are subject to the Compiere License Version 1.1
* ("License"); You may not use this file except in compliance with the License
* You may obtain a copy of the License at http://www.compiere.org/license.html
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
* The Original Code is Compiere ERP & CRM Business Solution
* The Initial Developer of the Original Code is Jorg Janke and ComPiere, Inc.
* Portions created by Jorg Janke are Copyright (C) 1999-2001 Jorg Janke, parts
* created by ComPiere are Copyright (C) ComPiere, Inc.; All Rights Reserved.
* Contributor(s): ______________________________________.
*****************************************************************************/
package org.compiere.model;
import java.sql.*;
import java.util.*;
import java.math.*;
import java.text.*;
import java.beans.*;
import java.io.*;
import org.compiere.util.ValueNamePair;
import org.compiere.util.*;
/**
* Tab Model.
* - a combination of AD_Tab (the display attributes) and AD_Table information.
* <p>
* The Tab owns also it's Table model
* and listens to data changes to update the Field values.
*
* <p>
* The Tab maintains the bound property: CurrentRow
*
* <pre>
* Event Hierarchies:
* - dataChanged (from MTable)
* - setCurrentRow
* - Update all Field Values
*
* - setValue
* - Update Field Value
* - Callout
* </pre>
* @author Jorg Janke
* @version $Id: MTab.java,v 1.41 2003/04/30 06:24:22 jjanke Exp $
*/
public final class MTab implements DataStatusListener, Serializable
{
/**
* Create Tab (Model) from Value Object.
* <p>
* MTab provides a property listener for changed rows and a
* DataStatusListener for communicating changes of the underlying data
* @param vo Value Object
*/
public MTab(MTabVO vo)
{
m_vo = vo;
// Create MTable
m_mTable = new MTable (m_vo.ctx, m_vo.TableName, m_vo.WindowNo, m_vo.TabNo, true);
m_mTable.setReadOnly(m_vo.IsReadOnly || m_vo.IsView);
m_mTable.setDeleteable(m_vo.IsDeleteable);
// Load Tab
// if (vo.TabNo == 0)
initTab(false);
// else
// {
// m_loader = new Loader();
// m_loader.setPriority(Thread.MIN_PRIORITY);
// m_loader.start();
// }
// waitLoadCompete();
} // M_Tab
/** Value Object */
private MTabVO m_vo;
/** The Table Model for Query */
private MTable m_mTable = null;
private String m_keyColumnName = "";
private String m_linkColumnName = "";
private String m_extendedWhere;
/** Attachments */
private HashMap m_Attachment = null;
/** Current Row */
private int m_currentRow = -1;
/** Property Change */
private PropertyChangeSupport m_propertyChangeSupport = new PropertyChangeSupport(this);
/** Property Change Type */
public static final String PROPERTY = "CurrentRow";
private Vector m_dataStatusListeners = null;
private DataStatusEvent m_DataStatusEvent = null;
//
private MQuery m_query = new MQuery();
private String m_oldQuery = "0=9";
private String m_linkValue = "999999";
/** Order By Array if SortNo 1..2 */
private String[] m_OrderBys = new String[2];
/** List of Key Parents */
private ArrayList m_parents = new ArrayList(2);
/** Map of ColumnName of source field (key) and the dependent field (value) */
private MultiMap m_depOnField = new MultiMap();
/** Async Loader */
private Loader m_loader = null;
/** Async Loading complete */
private volatile boolean m_loadComplete = false;
/*************************************************************************/
/**
* Tab loader for Tabs > 0
*/
class Loader extends Thread
{
/**
* Async Loading of Tab > 0
*/
public void run()
{
initTab (true);
} // run
} // Loader
/**
* Wait until load is complete
*/
private void waitLoadCompete()
{
if (m_loadComplete)
return;
//
m_loader.setPriority(Thread.NORM_PRIORITY);
Log.trace(Log.l1_User, "MTab.waitLoadComplete");
while (m_loader.isAlive())
{
try
{
Thread.sleep(100); // 1/10 sec
}
catch (Exception e)
{
Log.error("MTab.waitLoadComplete", e);
}
}
Log.trace(Log.l1_User, "MTab.waitLoadComplete - fini");
} // waitLoadComplete
/**
* Initialize Tab with record from AD_Tab_v
* @param async async
* @return true, if correctly initialized (ignored)
*/
private boolean initTab (boolean async)
{
Log.trace(Log.l3_Util, "MTab.initTab #" + m_vo.TabNo + " - Async=" + async);
m_extendedWhere = m_vo.WhereClause;
// Get Field Data
if (!loadFields())
{
m_loadComplete = true;
return false;
}
// Order By
m_mTable.setOrderClause(getOrderByClause(m_vo.onlyCurrentRows));
if (async)
Log.trace(Log.l3_Util, "MTab.initTab #" + m_vo.TabNo + " - Async=" + async, "fini");
m_loadComplete = true;
return true;
} // initTab
/**
* Dispose - clean up resources
*/
protected void dispose()
{
Log.trace(Log.l3_Util, "MTab.dispose #" + m_vo.TabNo);
m_OrderBys = null;
//
m_parents.clear();
m_parents = null;
//
m_mTable.close (true); // also disposes Fields
m_mTable = null;
//
m_depOnField.clear();
m_depOnField = null;
if (m_Attachment != null)
m_Attachment.clear();
m_Attachment = null;
//
m_vo.Fields.clear();
m_vo.Fields = null;
m_vo = null;
} // dispose
/**
* Get Field data and add to MTable, if it's required or displayed.
* Reqiored fields are keys, parents, or standard Columns
* @return true if fields loaded
*/
private boolean loadFields()
{
Log.trace(Log.l3_Util, "MTab.loadFields #" + m_vo.TabNo);
if (m_vo.Fields == null)
return false;
// Add RowID if this is not a view
if (!m_vo.IsView)
{
MField rowID = new MField (MFieldVO.createRowID (m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, m_vo.AD_Window_ID));
m_mTable.addField(rowID);
}
// Add Fields
for (int f = 0; f < m_vo.Fields.size(); f++)
{
MFieldVO voF = (MFieldVO)m_vo.Fields.get(f);
// Add Fields to Table
if (voF != null)
{
MField field = new MField (voF);
String columnName = field.getColumnName();
// Record Info
if (field.isKey())
{
if (m_vo.IsView) // make it a RowID for selection & update
voF.initRowID();
m_keyColumnName = columnName;
}
// Parent Column(s)
if (field.isParent())
m_parents.add(columnName);
// Order By
if (field.getSortNo() == 1)
m_OrderBys[0] = columnName;
else if (field.getSortNo() == 2)
m_OrderBys[1] = columnName;
// Add field
m_mTable.addField(field);
// List of ColumnNames, this field is dependent on
ArrayList list = field.getDependentOn();
for (int i = 0; i < list.size(); i++)
m_depOnField.put(list.get(i), field); // ColumnName, Field
// Add fields all fields are dependent on
if (columnName.equals("IsActive") || columnName.equals("Processed"))
m_depOnField.put(columnName, null);
}
} // for all fields
// Add Standard Fields
if (m_mTable.getField("Created") == null)
{
MField created = new MField (MFieldVO.createStdField(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, m_vo.AD_Window_ID, false, true, true));
m_mTable.addField(created);
}
if (m_mTable.getField("CreatedBy") == null)
{
MField createdBy = new MField (MFieldVO.createStdField(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, m_vo.AD_Window_ID, false, true, false));
m_mTable.addField(createdBy);
}
if (m_mTable.getField("Updated") == null)
{
MField updated = new MField (MFieldVO.createStdField(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, m_vo.AD_Window_ID, false, false, true));
m_mTable.addField(updated);
}
if (m_mTable.getField("UpdatedBy") == null)
{
MField updatedBy = new MField (MFieldVO.createStdField(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, m_vo.AD_Window_ID, false, false, false));
m_mTable.addField(updatedBy);
}
return true;
} // loadFields
/**
* Get TableModel.
* <B>Do not directly communicate with the table model,
* but through the methods of this class</B>
* @return Table Model
*/
public MTable getTableModel()
{
return m_mTable;
} // getTableModel
/**
* Get Tab Icon
* @return Icon
*/
public javax.swing.Icon getIcon()
{
if (m_vo.AD_Image_ID == 0)
return null;
//
/** @todo Load Image */
return null;
} // getIcon
/*************************************************************************/
/**
* Has this field dependents ?
* @param columnName column name
* @return true if column has dependent
*/
public boolean isDependentOn (String columnName)
{
// m_depOnField.printToLog();
return m_depOnField.containsKey(columnName);
} // isDependentOn
/**
* Get dependent fields of columnName
* @param columnName column name
* @return ArrayList with MFields dependent on columnName
*/
public ArrayList getDependentFieldList (String columnName)
{
return m_depOnField.getValues(columnName);
} // getDependentFieldList
/*************************************************************************/
/**
* Set Query
* @param query query
*/
public void setQuery(MQuery query)
{
if (query == null)
m_query = new MQuery();
else
m_query = query;
} // setQuery
/**
* Get Query
* @return query
*/
public MQuery getQuery()
{
return m_query;
} // getQuery
/**
* Is Query Active
* @return true if query active
*/
public boolean isQueryActive()
{
return m_query.isActive();
} // isQueryActive
/**
* Enable Events - enable data events of tabs (add listeners)
*/
public void enableEvents()
{
// Setup Events
m_mTable.addDataStatusListener(this);
// m_mTable.addTableModelListener(this);
} // enableEvents
/**
* Assemble whereClause and query MTable and position to row 0.
* <pre>
* Scenarios:
* - Never opened (full query)
* - query changed (full query)
* - Detail link value changed (full query)
* - otherwise (refreshAll)
* </pre>
* @param onlyCurrentRows only current rows (1 day)
*/
public void query (boolean onlyCurrentRows)
{
query (onlyCurrentRows, 1);
} // query
/**
* Assemble whereClause and query MTable and position to row 0.
* <pre>
* Scenarios:
* - Never opened (full query)
* - query changed (full query)
* - Detail link value changed (full query)
* - otherwise (refreshAll)
* </pre>
* @param onlyCurrentRows only current rows
* @param onlyCurrentDays if only current row, how many days back
*/
public void query (boolean onlyCurrentRows, int onlyCurrentDays)
{
Log.trace(Log.l3_Util, "MTab.query #" + m_vo.TabNo);
// is it same query?
boolean refresh = m_oldQuery.equals(m_query.getWhereClause())
&& m_vo.onlyCurrentRows == onlyCurrentRows && m_vo.onlyCurrentDays == onlyCurrentDays;
m_oldQuery = m_query.getWhereClause();
m_vo.onlyCurrentRows = onlyCurrentRows;
m_vo.onlyCurrentDays = onlyCurrentDays;
/**
* Set Where Clause
*/
// Tab Where Clause
StringBuffer where = new StringBuffer(m_vo.WhereClause);
// Detail Query
if (isDetail())
{
String lc = getLinkColumnName();
if (lc.equals(""))
Log.error("MTab.query - no link column");
else
{
String value = Env.getContext(m_vo.ctx, m_vo.WindowNo, lc);
// Same link value?
if (refresh)
refresh = m_linkValue.equals(value);
m_linkValue = value;
// Check validity
if (value.length() == 0)
Log.error("MTab.query - no value for link column " + lc);
else
{
// we have column and value
if (where.length() != 0)
where.append(" AND ");
where.append(lc).append("=");
if (lc.endsWith("_ID"))
where.append(value);
else
where.append("'").append(value).append("'");
}
}
} // isDetail
m_extendedWhere = where.toString();
// Final Query
if (m_query.isActive())
{
String q = validateQuery(m_query);
if (q != null)
{
if (where.length() > 0 )
where.append(" AND ");
where.append(q);
}
}
/**
* Query
*/
if (m_mTable.isOpen())
{
if (refresh)
m_mTable.dataRefreshAll();
else
m_mTable.dataRequery(where.toString(), m_vo.onlyCurrentRows && !isDetail(), onlyCurrentDays);
}
else
{
m_mTable.setWhereClause(where.toString(), m_vo.onlyCurrentRows && !isDetail(), onlyCurrentDays);
m_mTable.open();
}
// Go to Record 0
setCurrentRow(0, true);
} // query
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -