# -*- coding: utf-8 -*-

# Copyright (c) 2004 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing an UML like class widget.
"""

from qt import *
from qtcanvas import *

from UMLWidget import UMLWidget

class ClassModel:
    """
    Class implementing the class model.
    """
    def __init__(self, name, methods=[], attributes=[]):
        """
        Constructor
        
        @param name the class name (string)
        @param methods list of method names of the class
            (list of strings)
        @param attributes list of attribute names of the class
            (list of strings)
        """
        self.name = name
        self.methods = methods
        self.attributes = attributes
        
    def addMethod(self, method):
        """
        Method to add a method to the class model.
        
        @param method method name to be added (string)
        """
        self.methods.append(method)
        
    def addAttribute(self, attribute):
        """
        Method to add an attribute to the class model.
        
        @param attribute attribute name to be added (string)
        """
        self.attributes.append(attribute)
        
    def getMethods(self):
        """
        Method to retrieve the methods of the class.
        
        @return list of class methods (list of strings)
        """
        return self.methods[:]
        
    def getAttributes(self):
        """
        Method to retrieve the attributes of the class.
        
        @return list of class attributes (list of strings)
        """
        return self.attributes[:]
        
    def getName(self):
        """
        Method to retrieve the class name.
        
        @return class name (string)
        """
        return self.name
        
class ClassWidget(UMLWidget):
    """
    Class implementing an UML like class widget.
    """
    def __init__(self, canvas, model=None, external=0, x=0, y=0, rounded=0, noAttrs=0):
        """
        Constructor
        
        @param canvas canvas containing the class widget (QCanvas)
        @param model class model containing the class data (ClassModel)
        @param external flag indicating a class defined outside our scope (boolean)
        @param x x-coordinate (integer)
        @param y y-coordinate (integer)
        @keyparam rounded flag indicating a rounded corner (boolean)
        @keyparam noAttrs flag indicating, that no attributes should be shown (boolean)
        """
        UMLWidget.__init__(self, canvas, x, y, rounded)
        self.model = model
        self.external = external
        self.noAttrs = noAttrs
        
        if self.model:
            self.calculateSize()
        
        self.update()
        
    def calculateSize(self):
        """
        Method to calculate the size of the class widget.
        """
        if self.model is None:
            return
            
        attrs = self.model.getAttributes()
        meths = self.model.getMethods()
        
        font = QFont(self.font)
        font.setBold(1)
        font.setItalic(1)
        fm = QFontMetrics(font)
        
        # calculate height
        fontHeight = fm.lineSpacing() + 1 # one for the baseline itself
        lines = 1
        if not self.noAttrs:
            if attrs:
                lines += len(attrs)
            else:
                lines += 1
        if meths:
            lines += len(meths)
        else:
            lines += 1
        height = lines * fontHeight
        
        # calculate width
        width = fm.width(self.model.getName())
        
        if not self.noAttrs:
            for attr in attrs:
                w = fm.width(attr)
                width = max(w, width)
            
        for meth in meths:
            w = fm.width(meth)
            width = max(w, width)
        
        width += self.margin * 2
        width += 4  # a little bit more for strange fonts
        
        if self.noAttrs:
            height += self.margin * 4
        else:
            height += self.margin * 6
        
        self.setSize(width, height)
    
    def setModel(self, model):
        """
        Method to set the class model.
        
        @param model class model containing the class data (ClassModel)
        """
        self.model = model
        self.calculateSize()
        self.update()
        
    def drawShape(self, painter):
        """
        Overriden method to draw the shape.
        
        @param painter painter the shape is drawn to (QPainter)
        """
        painter.setPen(Qt.black)
        offsetX = self.x()
        offsetY = self.y()
        w = self.width()
        h = self.height()
        fm = QFontMetrics(self.font)
        fontHeight = fm.lineSpacing() + 1 # one for the baseline itself
        
        painter.drawRect(offsetX, offsetY, w, h)
        
        y = self.margin
        self.font.setBold(1)
        painter.setFont(self.font)
        painter.drawText(offsetX + self.margin,
                         offsetY + y,
                         w - self.margin * 2,
                         fontHeight,
                         Qt.AlignHCenter,
                         self.model.getName())
        y += fontHeight + self.margin
        self.font.setBold(0)
        painter.setFont(self.font)
        painter.drawLine(offsetX, offsetY + y,
                         offsetX + w - 1, offsetY + y)
        y += self.margin
        
        if self.external:
            painter.drawText(offsetX + self.margin,
                             offsetY + y,
                             w - self.margin * 2,
                             fontHeight,
                             Qt.AlignHCenter,
                             "")
            y += fontHeight
        else:
            if not self.noAttrs:
                attrs = self.model.getAttributes()
                if attrs:
                    for attr in attrs:
                        painter.drawText(offsetX + self.margin,
                                         offsetY + y,
                                         w - self.margin * 2,
                                         fontHeight,
                                         Qt.AlignHCenter,
                                         attr)
                        y += fontHeight
                else:
                    painter.drawText(offsetX + self.margin,
                                     offsetY + y,
                                     w - self.margin * 2,
                                     fontHeight,
                                     Qt.AlignHCenter,
                                     "")
                    y += fontHeight
                y += self.margin
                painter.drawLine(offsetX, offsetY + y,
                                 offsetX + w - 1, offsetY + y)
                y += self.margin
            
            meths = self.model.getMethods()
            if meths:
                for meth in meths:
                    painter.drawText(offsetX + self.margin,
                                     offsetY + y,
                                     w - self.margin * 2,
                                     fontHeight,
                                     Qt.AlignHCenter,
                                     meth)
                    y += fontHeight
            else:
                painter.drawText(offsetX + self.margin,
                                 offsetY + y,
                                 w - self.margin * 2,
                                 fontHeight,
                                 Qt.AlignHCenter,
                                 "")
                y += fontHeight
                
        if self.isSelected():
            self.drawSelected(painter, offsetX, offsetY)
        
    def isExternal(self):
        """
        Method returning the external state.
        
        @return external state (boolean)
        """
        return self.external
