# GNU Enterprise Forms - QT3 UI driver - Grid Widgets
#
# Copyright 2001-2009 Free Software Foundation
#
# This file is part of GNU Enterprise
#
# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 3, or (at your option) any later version.
#
# GNU Enterprise 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with program; see the file COPYING. If not,
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id: grid.py 9956 2009-10-11 18:54:57Z reinhard $

from PyQt4 import Qt as qt

from gnue.forms.uidrivers.qt4.widgets import _base

__all__ = ['UIGrid']

# =============================================================================
# Interface implementation for a grid widget
# =============================================================================

class UIGrid(_base.UIHelper):
    """
    The visual container for the grid control.
    """

    # -------------------------------------------------------------------------
    # Constructor
    # -------------------------------------------------------------------------

    def __init__(self, event):

        _base.UIHelper.__init__(self, event)
        self.__max = 0
        self.__visible = 0
        self.growable = True


    # -------------------------------------------------------------------------
    # Create a wx box widget
    # -------------------------------------------------------------------------

    def _create_widget_ (self, event, spacer):
        """
        Create the QWidget for the grid control and add it to the owner.
        The spacer is ignored for <grid> tags.

        @param event: the creation-event instance carrying information like
            container (parent-widget)
        @param spacer: not used for grid tags

        @returns: the QLayout instance used for adding the rows
        """
        parent = event.container

        self.widget = qt.QFrame(parent)

        hbox = qt.QHBoxLayout(self.widget, 2)

        self._container = ResizeContainer(self.widget, self)
        self.scroll = qt.QScrollBar(qt.Qt.Vertical, self.widget)

        hbox.addWidget(self._container, 1)
        hbox.addWidget(self.scroll, 0)

        self.rowsizer = qt.QGridLayout(self._container)

        self.__max = self._gfObject.rows
        self.__visible = self.__max

        self.__build_header()

        self.getParent().add_widgets(self, spacer)

        return None


    # -------------------------------------------------------------------------
    # Build the first row of the grid (the header)
    # -------------------------------------------------------------------------

    def __build_header(self):

        cols = {}
        linenum = 0
        for line in self._gfObject.findChildrenOfType('GFGridLine', True, True):
            index = 0
            for item in line._children:
                span = int(getattr(item, 'Sizer__span', 1))
                cols.setdefault(index, []).append(getattr(item, 'label', None))
                index += span
            linenum += 1

        colnum = cols.keys()
        colnum.sort()

        for clx in colnum:
            self.rowsizer.setColStretch(clx, 1)

            pnl = qt.QFrame(self._container)
            vbx = qt.QVBoxLayout(pnl)

            for label in cols[clx]:
                stc = qt.QLabel(label, pnl)
                vbx.addWidget(stc)

            self.rowsizer.addMultiCellWidget(pnl, 0, 0, clx, clx)


    # -------------------------------------------------------------------------
    # Get the row-number of a concrete gridline in the GridBagSizer
    # -------------------------------------------------------------------------

    def _get_row(self, line, record):
        """
        Get the row number of a concrete gridline in the QGridLayout
        @param line: the UIGridLine instance we're interested in
        @param record: the spacer (rel. record-number) of the line in question
        @returns: the row within the QGridLayout
        """

        return len(self._children) * record + self._children.index(line) + 1


    # -------------------------------------------------------------------------
    # Adjust scrollbar if the current record has changed
    # -------------------------------------------------------------------------

    def _ui_adjust_scrollbar_(self, position, size, count):
        """
        Adjust the thumb-position and the number of rows of the scrollbar
        """
        self.scroll.setMaxValue(count)
        self.scroll.setPageStep(size)
        self.scroll.setValue(position)


    # -------------------------------------------------------------------------
    # Add or remove records from the grid
    # -------------------------------------------------------------------------

    def update_records(self, num_recs):

        if num_recs > self.__visible:
            self.__add_new_records(num_recs - self.__visible)
            self._gfObject._event_rows_changed(self.__visible)
        else:
            self.__hide_records(self.__visible - num_recs)
            self._gfObject._event_rows_changed(self.__visible)


    # -------------------------------------------------------------------------
    # Add new records to the grid (after resizing it)
    # -------------------------------------------------------------------------

    def __add_new_records(self, num_recs):

        for index in range(num_recs):
            record = self.__visible + index

            if record >= self.__max:
                self.walk(self.__child_add_walker, record)
                self.__change_visibility(record, True)
                self.__max += 1
            else:
                self.__change_visibility(record, True)

        self.__visible += num_recs

        self._uiForm.main_window.updateGeometry()


    # -------------------------------------------------------------------------
    # Create all child-widgets
    # -------------------------------------------------------------------------

    def __child_add_walker(self, item, spacer):

        if item == self:
            return

        widget = item.create_widget(item._creationEvent, spacer)
        item.widgets.append(widget)


    # -------------------------------------------------------------------------
    # Show or hide grid lines
    # -------------------------------------------------------------------------

    def __change_visibility(self, record, state):

        grid = self._container.layout()

        for item in self._children:
            for panel in item._columns[record]:
                if state:
                    panel.show()
                else:
                    panel.hide()


    # -------------------------------------------------------------------------
    # Hide a given number of records
    # -------------------------------------------------------------------------

    def __hide_records(self, num_recs):

        for index in range(num_recs):
            self.__change_visibility(self.__visible-1, False)
            self.__visible -= 1

        self._uiForm.main_window.updateGeometry()


# =============================================================================
# Qt class implementing the grid-container
# =============================================================================

class ResizeContainer(qt.QWidget):
    def __init__(self, parent, ui_grid):
        qt.QWidget.__init__(self, parent)
        self.ui_grid = ui_grid

    def resizeEvent(self, event):
        qt.QWidget.resizeEvent(self, event)

        if not self.ui_grid._uiForm.sizing_enabled:
            return

        saved = self.ui_grid._uiForm.sizing_enabled
        self.ui_grid._uiForm.sizing_enabled = False
        try:
            header = self.layout().cellGeometry(0, 0)
            rech = 0
            for item in self.ui_grid._children:
                rech += max([panel.layout().minimumSize().height() \
                             for panel in item._columns[0]])
            available = self.size().height() - header.height()
            num_recs = available / rech

            self.ui_grid.update_records(num_recs)

        finally:
            self.ui_grid._uiForm.sizing_enabled = saved


# =============================================================================
# Configuration data
# =============================================================================

configuration = {
  'baseClass': UIGrid,
  'provides' : 'GFGrid',
  'container': 1
}
