/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.smart.dataui;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Timer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import com.servoy.j2db.FormController;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.dataprocessing.DBValueList;
import com.servoy.j2db.dataprocessing.FoundSetManager;
import com.servoy.j2db.dataprocessing.IFoundSetInternal;
import com.servoy.j2db.dataprocessing.ISaveConstants;
import com.servoy.j2db.dataprocessing.SortColumn;
import com.servoy.j2db.gui.LFAwareSortableHeaderRenderer;
import com.servoy.j2db.persistence.IColumnTypes;
import com.servoy.j2db.persistence.RepositoryException;
import com.servoy.j2db.persistence.Table;
import com.servoy.j2db.scripting.JSEvent;
import com.servoy.j2db.smart.TableView;
import com.servoy.j2db.ui.IEventExecutor;
import com.servoy.j2db.ui.ISupportValueList;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.Utils;
/**
* Default sorter for tableview
*
* @author jblok
*/
public class ColumnSortListener extends MouseAdapter
{
private final IApplication application;
private final TableView table;
private final FormController fc;//can be null if portal!
private final Map<Integer, Boolean> lastColumnIndex = new HashMap<Integer, Boolean>();
private boolean lastSortAsc = false;
private Timer sortTimer = null;
public ColumnSortListener(IApplication app, TableView table, FormController fc)
{
this.application = app;
this.table = table;
this.fc = fc;
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
*/
@Override
public void mouseReleased(MouseEvent e)
{
}
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
*/
@Override
public void mouseClicked(final MouseEvent e)
{
if (!table.isEnabled()) return;
if (e.getButton() == MouseEvent.BUTTON1)
{
if (fc != null) fc.setLastKeyModifiers(e.getModifiers());
TableColumnModel colModel = table.getColumnModel();
if (colModel == null)
{
return;
}
int columnModelIndex = colModel.getColumnIndexAtX(e.getX());
if (columnModelIndex < 0)
{
return;
}
final TableColumn column = colModel.getColumn(columnModelIndex);
if (column == null)
{
return;
}
int modelIndex = column.getModelIndex();
if (modelIndex < 0)
{
return;
}
if (table.getModel() instanceof IFoundSetInternal &&
application.getFoundSetManager().getEditRecordList().stopIfEditing((IFoundSetInternal)table.getModel()) != ISaveConstants.STOPPED)
{
return;
}
Integer columnIndex = Integer.valueOf(columnModelIndex);
if (lastColumnIndex.containsKey(columnIndex))
{
lastSortAsc = !lastColumnIndex.get(columnIndex).booleanValue();
}
else
{
lastSortAsc = true;
if (fc != null && column instanceof CellAdapter && ((CellAdapter)column).getDataProviderID() != null && e.getClickCount() <= 1 &&
table.getModel() instanceof IFoundSetInternal)
{
IFoundSetInternal foundset = (IFoundSetInternal)table.getModel();
List<SortColumn> sortCols = foundset.getSortColumns();
if (sortCols != null && sortCols.size() > 0)
{
CellAdapter ca = (CellAdapter)column;
List<String> sortingProviders = null;
Component renderer = ca.getRenderer();
if (renderer instanceof ISupportValueList && ((ISupportValueList)renderer).getValueList() != null)
{
try
{
sortingProviders = DBValueList.getShowDataproviders(((ISupportValueList)renderer).getValueList().getValueList(),
(Table)foundset.getTable(), ca.getDataProviderID(), application.getFoundSetManager());
}
catch (RepositoryException ex)
{
Debug.error(ex);
}
}
if (sortingProviders == null)
{
// no related sort, use sort on dataProviderID instead
sortingProviders = Collections.singletonList(ca.getDataProviderID());
}
for (String sortingProvider : sortingProviders)
{
SortColumn existingSc;
try
{
FoundSetManager fsm = (FoundSetManager)foundset.getFoundSetManager();
existingSc = fsm.getSortColumn(foundset.getTable(), sortingProvider, false);
}
catch (Exception ex)
{
Debug.error(ex);
continue;
}
for (SortColumn sc : sortCols)
{
if (sc.equalsIgnoreSortorder(existingSc))
{
lastSortAsc = sc.getSortOrder() == SortColumn.DESCENDING;
}
}
}
}
}
}
if (!e.isShiftDown())
{
// clear previous data
lastColumnIndex.clear();
}
lastColumnIndex.put(columnIndex, Boolean.valueOf(lastSortAsc));
if (column instanceof CellAdapter && table.getModel() instanceof IFoundSetInternal)
{
try
{
if (sortTimer != null)
{
sortTimer.stop();
}
sortTimer = new Timer(300, new AbstractAction()
{
public void actionPerformed(ActionEvent event)
{
try
{
String dataProviderID = ((CellAdapter)column).getDataProviderID();
int labelForOnActionMethodId = 0;
if (((CellAdapter)column).getHeaderRenderer() instanceof LFAwareSortableHeaderRenderer)
{
labelForOnActionMethodId = ((LFAwareSortableHeaderRenderer)((CellAdapter)column).getHeaderRenderer()).getOnActionMethodID();
}
if (fc != null && labelForOnActionMethodId > 0)
{
LFAwareSortableHeaderRenderer renderer = (LFAwareSortableHeaderRenderer)(((CellAdapter)column).getHeaderRenderer());
fc.executeFunction(
String.valueOf(labelForOnActionMethodId),
Utils.arrayMerge((new Object[] { getJavaScriptEvent(e, JSEvent.EventType.action, renderer.getName()) }),
Utils.parseJSExpressions(renderer.getInstanceMethodArguments("onActionMethodID"))), true, null, false, "onActionMethodID"); //$NON-NLS-1$//$NON-NLS-2$
}
else if (fc != null && fc.getForm().getOnSortCmdMethodID() > 0)
{
// Also execute the on sort command on none data providers (like a label) then they can do there own sort.
fc.executeFunction(
String.valueOf(fc.getForm().getOnSortCmdMethodID()),
Utils.arrayMerge(
(new Object[] { dataProviderID, Boolean.valueOf(lastSortAsc), getJavaScriptEvent(e, JSEvent.EventType.none, null) }),
Utils.parseJSExpressions(fc.getForm().getInstanceMethodArguments("onSortCmdMethodID"))), true, null, false, "onSortCmdMethodID"); //$NON-NLS-1$//$NON-NLS-2$
}
else if (dataProviderID != null && fc.getForm().getOnSortCmdMethodID() != -1)
{
List<String> sortingProviders = null;
IFoundSetInternal model = (IFoundSetInternal)table.getModel();
Component renderer = ((CellAdapter)column).getRenderer();
if (renderer instanceof ISupportValueList && ((ISupportValueList)renderer).getValueList() != null)
{
try
{
sortingProviders = DBValueList.getShowDataproviders(((ISupportValueList)renderer).getValueList().getValueList(),
(Table)model.getTable(), dataProviderID, application.getFoundSetManager());
}
catch (RepositoryException ex)
{
Debug.error(ex);
}
}
if (sortingProviders == null)
{
// no related sort, use sort on dataProviderID instead
sortingProviders = Collections.singletonList(dataProviderID);
}
try
{
List<SortColumn> list = e.isShiftDown() ? model.getSortColumns() : new ArrayList<SortColumn>();
for (String sortingProvider : sortingProviders)
{
FoundSetManager fsm = ((FoundSetManager)model.getFoundSetManager());
SortColumn sc = fsm.getSortColumn(model.getTable(), sortingProvider, false);
if (sc != null && sc.getColumn().getDataProviderType() != IColumnTypes.MEDIA)
{
for (SortColumn oldColumn : list)
{
if (oldColumn.equalsIgnoreSortorder(sc))
{
sc = oldColumn;
break;
}
}
if (!list.contains(sc)) list.add(sc);
sc.setSortOrder(lastSortAsc ? SortColumn.ASCENDING : SortColumn.DESCENDING);
}
model.sort(list, false);
}
}
catch (Exception ex)
{
Debug.error(ex);
}
}
}
finally
{
sortTimer.stop();
}
}
});
sortTimer.start();
}
catch (Exception ex)
{
Debug.error(ex);
}
}
}
}
@Override
public void mousePressed(MouseEvent e)
{
if (!table.isEnabled()) return;
if (e.getButton() == MouseEvent.BUTTON1)
{
application.getFoundSetManager().getEditRecordList().stopEditing(false);
}
}
public JSEvent getJavaScriptEvent(MouseEvent e, JSEvent.EventType type, String sourceName)
{
JSEvent event = new JSEvent();
event.setType(type);
if (fc != null) event.setFormName(fc.getName());
event.setElementName(sourceName);
event.setModifiers(e.getModifiers() == IEventExecutor.MODIFIERS_UNSPECIFIED ? 0 : e.getModifiers());
return event;
}
}