
from qt import *
from tdecore import *
from tdeui import *
import os
from displayconfigabstraction import *

# Running as the root user or not?
isroot = os.getuid()==0

############################################################################
class ResizeSlider(QVGroupBox):
    """ An abstracted QSlider in a nice box to change the resolution of a screen """
    def __init__(self,parent):
        # Screen size group
        QVGroupBox.__init__(self,parent)
        self.updating_gui = True
        self._buildGUI()
        self.updating_gui = False

    def _buildGUI(self):
        self.setTitle(i18n("Screen Size"))
        self.setInsideSpacing(KDialog.spacingHint())
        self.setInsideMargin(KDialog.marginHint())

        hbox3 = QHBox(self)
        hbox3.setSpacing(KDialog.spacingHint())
        label = QLabel(hbox3,"textLabel2_4")
        label.setText(i18n("Lower"))
        self.screensizeslider = QSlider(hbox3,"slider1")
        self.screensizeslider.setMinValue(0)
        self.screensizeslider.setMaxValue(4)
        self.screensizeslider.setPageStep(1)
        self.screensizeslider.setOrientation(QSlider.Horizontal)
        self.screensizeslider.setTickmarks(QSlider.Below)
        self.connect(self.screensizeslider,SIGNAL("valueChanged(int)"),self.slotResolutionChange)
        label = QLabel(hbox3)
        label.setText(i18n("Higher"))

        self.resolutionlabel = QLabel(self)
        self.resolutionlabel.setText("640x400")

    def setScreen(self, screen):
        self.updating_gui = True
        self.screen = screen
        self.screensizeslider.setMaxValue(len(screen.getAvailableResolutions())-1)
        self.screensizeslider.setValue(screen.getResolutionIndex())
        self.updating_gui = False
        self.setResolutionIndex(screen.getResolutionIndex())

    def slotResolutionChange(self,i):
        """ Pass signal from slider through to App """
        if self.updating_gui:
            return
        self.setResolutionIndex(i)
        self.emit(PYSIGNAL("resolutionChange(int)"),(i,))

    def setMaxValue(self,value):
        self.updating_gui = True
        self.screensizeslider.setMaxValue(value)
        self.updating_gui = False

    def setMinValue(self,value):
        self.updating_gui = True
        self.screensizeslider.setMinValue(value)
        self.updating_gui = False

    def setValue(self,value):
        self.updating_gui = True
        self.screensizeslider.setValue(value)
        self.updating_gui = False

    def value(self):
        return self.screensizeslider.value()

    def setResolutionLabel(self,text):
        self.resolutionlabel.setText(text) 

    def setResolutionIndex(self,i):
        self.updating_gui = True
        width,height = self.screen.getAvailableResolutions()[i]
        self.setResolutionLabel(i18n("%1 x %2").arg(width).arg(height))
        self.updating_gui = False

############################################################################
class MonitorPreview(QWidget):
    """ A ResizableMonitor is an Image in a grid which has resizable edges, 
        fixed-size corners and is thus expandable. """
    ROTATE_0 = 0
    ROTATE_90 = 1
    ROTATE_180 = 2
    ROTATE_270 = 3

    def __init__(self, parent=None, imagedir="", name=None):
        QWidget.__init__(self,parent)

        self.rotation = MonitorPreview.ROTATE_0

        self.screen_width = 1280
        self.screen_height = 1024

        self.reflect_x = False
        self.reflect_y = False

        self.setBackgroundMode(Qt.NoBackground)

        self.imagedir = imagedir + "monitor_resizable/"

        self.image_monitor = QPixmap(self.imagedir+"monitor.png")
        self.image_monitor_wide = QPixmap(self.imagedir+"monitor_wide.png")
        self.image_monitor_r90 = QPixmap(self.imagedir+"monitor_r90.png")
        self.image_monitor_wide_r90 = QPixmap(self.imagedir+"monitor_wide_r90.png")

        self.image_background = QPixmap(self.imagedir+"background.png")
        self.image_background_wide = QPixmap(self.imagedir+"background_wide.png")
        self.image_background_r90 = QPixmap(self.imagedir+"background_r90.png")
        self.image_background_wide_r90 = QPixmap(self.imagedir+"background_wide_r90.png")

        self.image_window = QPixmap(self.imagedir+"window_4th.png")
        self.image_window_bottom_left = QPixmap(self.imagedir+"window_bottom_left_4th.png")
        self.image_window_bottom_right = QPixmap(self.imagedir+"window_bottom_right_4th.png")

    def sizeHint(self):
        max_width = max(self.image_monitor.width(), self.image_monitor_wide.width(),
                        self.image_monitor_r90.width(), self.image_monitor_wide_r90.width())
        max_height = max(self.image_monitor.height(), self.image_monitor_wide.height(),
                        self.image_monitor_r90.height(), self.image_monitor_wide_r90.height())
        return QSize(max_width, max_height)

    def sizePolicy(self):
        return QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

    def paintEvent(self,paint_event):
        screen_width = self.screen_width
        screen_height = self.screen_height

        # Widescreen format: preview width: 176, height: 99, 16:9
        is_wide = abs(float(screen_width)/float(screen_height)-16.0/9.0) < 0.2

        if not is_wide:
            preview_screen_width = 152
            preview_screen_height = 114
        else:
            preview_screen_width = 176
            preview_screen_height = 99

        if self.rotation==MonitorPreview.ROTATE_0 or self.rotation==MonitorPreview.ROTATE_180:
            # Normal, landscape orientation.
            if not is_wide:
                screen_x_offset = 23
                screen_y_offset = 15
                image_background = self.image_background
            else:
                screen_x_offset = 23
                screen_y_offset = 29
                image_background = self.image_background_wide
        else:
            # Portrait orientation. Swap some values around.
            t = preview_screen_width
            preview_screen_width = preview_screen_height
            preview_screen_height = t

            t = screen_width
            screen_width = screen_height
            screen_height = t

            if not is_wide:
                screen_x_offset = 42
                screen_y_offset = 15
                image_background = self.image_background_r90
            else:
                screen_x_offset = 50
                screen_y_offset = 15
                image_background = self.image_background_wide_r90

        # Draw everything off screen in a buffer
        preview_buffer = QPixmap(preview_screen_width,preview_screen_height)
        painter = QPainter(preview_buffer)

        # Draw the background on the monitor's screen
        painter.drawPixmap(0, 0, image_background)

        # Work out the scaling factor for the eye candy in the preview winodw.
        scale_factor = 4.0*float(preview_screen_width) / float(screen_width)
        transform_matrix = QWMatrix().scale(scale_factor,scale_factor)

        # Draw the little window on the background
        scaled_window = self.image_window.xForm(transform_matrix)

        sx = (preview_screen_width-scaled_window.width())/2
        sy = (preview_screen_height-scaled_window.height())/2
        if sx < 0:
            sx = 0 
        if sy < 0:
            sy = 0
        sw = scaled_window.width()
        if sw>preview_screen_width:
            sw = preview_screen_width

        sh = scaled_window.height()
        if sh>preview_screen_height:
            sh = preview_screen_height

        painter.drawPixmap(sx, sy, scaled_window, 0, 0, sw, sh)

        # Now draw the clock in the lower right corner
        scaled_window = self.image_window_bottom_right.xForm(transform_matrix)

        sx = preview_screen_width - scaled_window.width()
        sy = preview_screen_height - scaled_window.height()
        sw = scaled_window.width()#preview_screen_width/2
        sh = scaled_window.height()

        sx_offset = 0
        if sx<0: # Some simple clipping for the left edge
            sx_offset = -sx
            sw = preview_screen_width
            sx = 0

        painter.drawPixmap(sx, sy, scaled_window, sx_offset, 0, sw, sh)

        # Now draw the k menu in the lower left corner
        scaled_window = self.image_window_bottom_left.xForm(transform_matrix)

        sx = 0
        sy = preview_screen_height - scaled_window.height()
        sw = preview_screen_width/2 # Just draw on the left side of the preview.
        sh = scaled_window.height()
        painter.drawPixmap(sx, sy, scaled_window, 0, 0, sw, sh)
        painter.end()

        # Transform the preview image. Do reflections.
        reflect_x = 1
        if self.reflect_x:
            reflect_x = -1
        reflect_y = 1
        if self.reflect_y:
            reflect_y = -1

        preview_buffer = preview_buffer.xForm(QWMatrix().scale(reflect_x,reflect_y))

        # Draw the monitor on another buffer.
        off_screen_buffer = QPixmap(self.width(),self.height())
        off_screen_painter = QPainter(off_screen_buffer)

        # Erase the buffer first
        off_screen_painter.setBackgroundColor(self.paletteBackgroundColor())
        off_screen_painter.eraseRect(0, 0, off_screen_buffer.width(), off_screen_buffer.height())

        if self.rotation==MonitorPreview.ROTATE_0 or self.rotation==MonitorPreview.ROTATE_180:
            if not is_wide:
                image_monitor = self.image_monitor
            else:
                image_monitor = self.image_monitor_wide
        else:
            if not is_wide:
                image_monitor = self.image_monitor_r90
            else:
                image_monitor = self.image_monitor_wide_r90

        top_edge = self.height()-image_monitor.height()
        left_edge = (self.width()-image_monitor.width())/2

        # Draw the monitor
        off_screen_painter.drawPixmap(left_edge, top_edge, image_monitor)
        off_screen_painter.end()

        # Copy the preview onto the off screen buffer with the monitor.
        bitBlt(off_screen_buffer, left_edge+screen_x_offset, top_edge+screen_y_offset, preview_buffer,
                0, 0, preview_buffer.width(), preview_buffer.height(),Qt.CopyROP, False)

        # Update the widget
        bitBlt(self, 0, 0, off_screen_buffer, 0, 0, self.width(), self.height(), Qt.CopyROP, False)

    def setResolution(self,width,height):
        self.screen_width = width
        self.screen_height = height
        self.update()

    def setRotation(self, rotation):
        self.rotation = rotation
        self.update()

    def setReflectX(self, enable):
        self.reflect_x = enable
        self.update()

    def setReflectY(self, enable):
        self.reflect_y = enable
        self.update()

############################################################################
class DualMonitorPreview(QWidget):
    """ This is the Widget to use elsewhere. It consists of a canvas and an
        arbitrary number of gizmos on the canvas. The gizmos can be dragged and 
        dropped around. Painting is double-buffered so flickering should not occur.
    """
    def __init__(self, parent, size, imagedir):
        QWidget.__init__(self,parent)
        self.setBackgroundMode(Qt.NoBackground)

        self.imagedir = imagedir + "dualhead/"
        self.snap_distance = 25
        self.snapping = True
        self.size = size
        self.position = XSetup.POSITION_LEFTOF

        self.current_screen = 0

        self.resize(size,size)
        self.setMouseTracking(True)

        self.gizmos = []
        self.gizmos.append(MovingGizmo("Monitor 1","monitor_1.png",QPoint(20,50),self.imagedir))
        self.gizmos.append(MovingGizmo("Monitor 2","monitor_2.png",QPoint(180,50),self.imagedir))

        self.gizmos[0].setWidth(1280)
        self.gizmos[0].setHeight(1024)
        self.gizmos[0].setHighlightColor(self.colorGroup().highlight())
        self.gizmos[1].setWidth(1280)
        self.gizmos[1].setHeight(1024)
        self.gizmos[1].setHighlightColor(self.colorGroup().highlight())

        self.dragging = False
        self.dragging_gizmo = 0
        self.drag_handle = None

        self._positionGizmos()
        self.setCurrentScreen(0)

    def minimumSizeHint(self):
        return QSize(self.size,self.size)

    def setCurrentScreen(self,screen):
        self.current_screen = screen
        self.gizmos[0].setHighlight(screen==0)
        self.gizmos[1].setHighlight(screen==1)
        self.update()

    def getCurrentScreen(self):
        return self.current_screen

    def setPosition(self,position):
        self.position = position
        self._positionGizmos()
        self.update()

    def getPosition(self):
        """Returns one of XSetup.POSITION_LEFTOF, XSetup.POSITION_RIGHTOF,
        XSetup.POSITION_ABOVE or XSetup.POSITION_BELOW.
        """
        return self.position

    def setScreenResolution(self,screenNumber,width,height):
        self.gizmos[screenNumber].setWidth(width)
        self.gizmos[screenNumber].setHeight(height)
        self.setPosition(self.position) # Reposition and force update.

    def _positionGizmos(self):
        g1 = self.gizmos[0]
        g2 = self.gizmos[1]

        # Treat POSITION_RIGHTOF and POSITION_BELOW as LEFTOF and ABOVE with the
        # gizmos swapped around.
        if self.position==XSetup.POSITION_RIGHTOF or self.position==XSetup.POSITION_BELOW:
            tmp = g1
            g1 = g2
            g2 = tmp

        if self.position==XSetup.POSITION_LEFTOF or self.position==XSetup.POSITION_RIGHTOF:
            x = -g1.getWidth()
            y = -max(g1.getHeight(), g2.getHeight())/2
            g1.setPosition(QPoint(x,y))

            x = 0
            g2.setPosition(QPoint(x,y))

        else:
            x = -max(g1.getWidth(), g2.getWidth())/2
            y = -g1.getHeight()
            g1.setPosition(QPoint(x,y))

            y = 0
            g2.setPosition(QPoint(x,y))

    def mousePressEvent(self,event):
        # Translate the point in the window into our gizmo space.
        world_point = self._getGizmoMatrix().invert()[0].map(event.pos())

        # If the mouse is in the air space of a gizmo, then we change the cursor to
        # indicate that the gizmo can be dragged.
        for giz in self.gizmos:
            if giz.getRect().contains(world_point):
                self.setCurrentScreen(self.gizmos.index(giz))
                break
        else:
            return

        # Pressing down the mouse button on a gizmo also starts a drag operation.
        self.dragging = True
        self.dragging_gizmo = self.getCurrentScreen()
        self.drag_handle = world_point - self.gizmos[self.dragging_gizmo].getPosition()

        # Let other people know that a gizmo has been selected.
        self.emit(PYSIGNAL("pressed()"), (self.current_screen,) )

    def mouseReleaseEvent(self,event):
        if not self.dragging:
            return

        # Translate the point in the window into our gizmo space.
        world_point = self._getGizmoMatrix().invert()[0].map(event.pos())

        if self._moveGizmo(world_point):
            self.setPosition(self.drag_position)
            self.emit(PYSIGNAL("positionChanged()"), (self.position,) )
        else:
            self.setPosition(self.position)
        self.dragging = False

    def mouseMoveEvent(self,event):
        # Translate the point in the window into our gizmo space.
        world_point = self._getGizmoMatrix().invert()[0].map(event.pos())

        # If the mouse is in the air space of a gizmo, then we change the cursor to
        # indicate that the gizmo can be dragged.
        for giz in self.gizmos:
            if giz.getRect().contains(world_point):
                self.setCursor(QCursor(Qt.SizeAllCursor))
                break
        else:
            self.unsetCursor()

        if self.dragging:
            self._moveGizmo(world_point)
            self.update()

        return

    def _moveGizmo(self,worldPoint):
        new_drag_position = worldPoint-self.drag_handle

        # Drag gizmo is simply the thing being dragged.
        drag_gizmo = self.gizmos[self.dragging_gizmo]
        drag_x = new_drag_position.x()
        drag_y = new_drag_position.y()

        # Snap gizmo is other (stationary) thing that we "snap" against.
        snap_gizmo = self.gizmos[1-self.dragging_gizmo]
        snap_x = snap_gizmo.getPosition().x()
        snap_y = snap_gizmo.getPosition().y()

        # Calculate the list of "snap points".
        snap_points = [
            (snap_x-drag_gizmo.getWidth(), snap_y),     # Left of 
            (snap_x+snap_gizmo.getWidth(), snap_y),     # Right of 
            (snap_x, snap_y-drag_gizmo.getHeight()),    # Above
            (snap_x, snap_y+snap_gizmo.getHeight())]    # Below

        # Find the snap point that the drag gizmo is closest to.
        best_index = -1
        best_distance = 0
        i = 0
        for snap_point in snap_points:
            dx = snap_point[0] - drag_x
            dy = snap_point[1] - drag_y
            distance_squared = dx*dx + dy*dy
            if best_index==-1 or distance_squared < best_distance:
                best_index = i
                best_distance = distance_squared
            i += 1

        # Lookup the best dualhead position that this configuration matches.
        if self.dragging_gizmo==0:
            self.drag_position = [
                XSetup.POSITION_LEFTOF,
                XSetup.POSITION_RIGHTOF,
                XSetup.POSITION_ABOVE,
                XSetup.POSITION_BELOW][best_index]
        else:
            self.drag_position = [
                XSetup.POSITION_RIGHTOF,
                XSetup.POSITION_LEFTOF,
                XSetup.POSITION_BELOW,
                XSetup.POSITION_ABOVE][best_index]

        # Convert the auto-snap distance in pixels into a distance in the gizmo coordinate system.
        world_snap_distance = self.snap_distance / self._getGizmoToPixelsScaleFactor()

        # Should this drag gizmo visually snap?
        snapped = False
        if best_distance <= (world_snap_distance*world_snap_distance):
            new_drag_position = QPoint(snap_points[best_index][0],snap_points[best_index][1])
            snapped = True

        # Move the gizmo
        self.gizmos[self.dragging_gizmo].setPosition(new_drag_position)

        return snapped

    def paintEvent(self,event=None):
        QWidget.paintEvent(self,event)

        # Paint to an off screen buffer first. Later we copy it to widget => flicker free.
        off_screen_buffer = QPixmap(self.width(),self.height())
        off_screen_painter = QPainter(off_screen_buffer)

        # Erase the buffer first
        off_screen_painter.setBackgroundColor(self.colorGroup().mid() )
        off_screen_painter.eraseRect(0, 0, off_screen_buffer.width(), off_screen_buffer.height())

        # 
        off_screen_painter.setWorldMatrix(self._getGizmoMatrix())

        # Paint the non-selected gizmo first.
        self.gizmos[ 1-self.current_screen ].paint(off_screen_painter)

        # Now paint the selected gizmo
        self.gizmos[self.current_screen].paint(off_screen_painter)

        # Turn off the world matrix transform.
        off_screen_painter.setWorldXForm(False)

        # Draw the rounded border
        off_screen_painter.setPen(QPen(self.colorGroup().dark(),1))
        off_screen_painter.drawRoundRect(0,0,self.width(),self.height(),2,2)

        off_screen_painter.end()

        # Update the widget
        bitBlt(self, 0, 0, off_screen_buffer, 0, 0, self.width(), self.height(), Qt.CopyROP, False)

    def _getGizmoMatrix(self):
        matrix = QWMatrix()
        matrix.translate(self.width()/2,self.height()/2)

        scale_factor = self._getGizmoToPixelsScaleFactor()
        matrix.scale(scale_factor,scale_factor)
        return matrix

    def _getGizmoToPixelsScaleFactor(self):
        g1 = self.gizmos[0]
        g2 = self.gizmos[1]
        size = min(self.width(),self.height())
        vscale = float(self.height()) / (2.1 * (g1.getHeight()+g2.getHeight()))
        hscale = float(self.width()) / (2.1 * (g1.getWidth()+g2.getWidth()))
        return min(vscale,hscale)

############################################################################
class MovingGizmo(object):
    """A gizmo represents a screen/monitor. It also has a width and height that
    correspond to the resolution of screen."""

    def __init__(self,label,filename,initial_pos=QPoint(0,0),imagedir="."):
        self.width = 100
        self.height = 100
        self.pixmap = QPixmap(imagedir+filename)

        self.highlight = False
        self.highlight_color = QColor(255,0,0)

        self.setPosition(initial_pos)

        # Used for caching the scaled pixmap.
        self.scaled_width = -1
        self.scaled_height = -1

    def setHighlight(self,enable):
        self.highlight = enable

    def setHighlightColor(self,color):
        self.highlight_color = color

    def setPosition(self,position):
        self.position = position

    def getSize(self):
        return QSize(self.width,self.height)

    def getPosition(self):
        return self.position

    def getRect(self):
        return QRect(self.position,self.getSize())

    def setWidth(self,width):
        self.width = width

    def getWidth(self):
        return self.width

    def setHeight(self,height):
        self.height = height

    def getHeight(self):
        return self.height

    def paint(self,painter):
        painter.save()
        if self.highlight:
            pen = QPen(self.highlight_color,6)
            painter.setPen(pen)

            painter.drawRect(self.position.x(), self.position.y(), self.width, self.height)

        to_pixels_matrix = painter.worldMatrix()
        top_left_pixels = to_pixels_matrix.map(self.position)
        bottom_right_pixels = to_pixels_matrix.map( QPoint(self.position.x()+self.width, self.position.y()+self.height) )

        # Scale the pixmap.
        scaled_width = bottom_right_pixels.x() - top_left_pixels.x()
        scaled_height = bottom_right_pixels.y() - top_left_pixels.y()

        if (scaled_width,scaled_height) != (self.scaled_width,self.scaled_height):
            scale_matrix = QWMatrix()
            scale_matrix.scale(
                float(scaled_width)/float(self.pixmap.width()),
                float(scaled_height)/float(self.pixmap.height()) )

            self.scaled_pixmap = self.pixmap.xForm(scale_matrix)
            (self.scaled_width,self.scaled_height) = (scaled_width,scaled_height)

        # Paste in the scaled pixmap.
        bitBlt(painter.device(), top_left_pixels.x(), top_left_pixels.y(), self.scaled_pixmap, 0, 0,
            self.scaled_pixmap.width(), self.scaled_pixmap.height(),Qt.CopyROP, False)

        painter.restore()

############################################################################
class GfxCardWidget(QVGroupBox):
    def __init__(self, parent, xsetup, gfxcard, gfxcarddialog, monitordialog):
        global imagedir
        QVGroupBox.__init__(self,parent)

        self.xsetup = xsetup
        self.gfxcard = gfxcard
        self.gfxcarddialog = gfxcarddialog
        self.monitordialog = monitordialog
        self._buildGUI()
        self._syncGUI()

    def _buildGUI(self):
        # Create the GUI    

        gridwidget = QWidget(self)
        grid = QGridLayout(gridwidget,2+3*len(self.gfxcard.getScreens()))
        grid.setSpacing(KDialog.spacingHint())
        grid.setColStretch(0,0)
        grid.setColStretch(1,0)
        grid.setColStretch(2,0)
        grid.setColStretch(3,1)
        grid.setColStretch(4,0)

        gfxcardpic = QLabel(gridwidget)
        gfxcardpic.setPixmap(UserIcon('hi32-gfxcard'))
        grid.addMultiCellWidget(gfxcardpic,0,1,0,0)

        label = QLabel(gridwidget)
        label.setText(i18n("Graphics card:"))
        grid.addWidget(label,0,1)

        self.gfxcardlabel = QLabel(gridwidget)
        grid.addWidget(self.gfxcardlabel,0,2)

        label = QLabel(gridwidget)
        label.setText(i18n("Driver:"))
        grid.addWidget(label,1,1)

        self.driverlabel = QLabel(gridwidget)
        grid.addMultiCellWidget(self.driverlabel,1,1,2,3)

        gfxbutton = QPushButton(gridwidget)
        gfxbutton.setText(i18n("Configure..."))
        self.connect(gfxbutton,SIGNAL("clicked()"),self.slotGfxCardConfigureClicked)
        grid.addWidget(gfxbutton,0,4)
        gfxbutton.setEnabled(self.xsetup.mayModifyXorgConfig())

        # Add all of the screens
        row = 2
        count = 1
        self.monitorlabels = []
        self.monitor_buttons = []
        self.monitor_roles = []
        for screen in self.gfxcard.getScreens():
            frame = QFrame(gridwidget)
            frame.setFrameShape(QFrame.HLine)
            frame.setFrameShadow(QFrame.Sunken)
            grid.addMultiCellWidget(frame,row,row,0,4)
            row += 1

            monitorpic = QLabel(gridwidget)
            monitorpic.setPixmap(UserIcon('hi32-display'))
            grid.addMultiCellWidget(monitorpic,row,row+1,0,0)

            # Monitor label
            label = QLabel(gridwidget)
            if len(self.gfxcard.getScreens())==1:
                label.setText(i18n("Monitor:"))
            else:
                label.setText(i18n("Monitor #%1:").arg(count))
            grid.addWidget(label,row,1)

            self.monitorlabels.append(QLabel(gridwidget))
            grid.addMultiCellWidget(self.monitorlabels[-1],row,row,2,3)

            # Role pulldown
            if len(self.xsetup.getAllScreens())!=1:
                label = QLabel(gridwidget)
                label.setText(i18n("Role:"))
                grid.addWidget(label,row+1,1)

                role_combo = KComboBox(False,gridwidget)
                role_combo.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
                self.monitor_roles.append(role_combo)
                role_combo.insertItem(i18n("Primary (1)"))
                role_combo.insertItem(i18n("Secondary (2)"))
                if len(self.xsetup.getAllScreens())>=3:
                    role_combo.insertItem(i18n("Unused"))
                self.connect(role_combo,SIGNAL("activated(int)"),self.slotRoleSelected)
                grid.addWidget(role_combo,row+1,2)
                role_combo.setEnabled(self.xsetup.mayModifyXorgConfig())

            monitorbutton = QPushButton(gridwidget)
            self.monitor_buttons.append(monitorbutton)
            monitorbutton.setText(i18n("Configure..."))
            self.connect(monitorbutton,SIGNAL("clicked()"),self.slotMonitorConfigureClicked)
            grid.addWidget(monitorbutton,row,4)
            monitorbutton.setEnabled(self.xsetup.mayModifyXorgConfig())
            row += 2
            count += 1

    def syncConfig(self):
        self._syncGUI()

    def _syncGUI(self):
        if self.gfxcard.getGfxCardModel() is not None:
            self.setTitle(self.gfxcard.getGfxCardModel().getName())
            self.gfxcardlabel.setText(self.gfxcard.getGfxCardModel().getName())

            if self.gfxcard.isProprietaryDriver():
                try:
                    # Displayconfig thinks there is a proprietary driver
                    self.driverlabel.setText(self.gfxcard.getGfxCardModel().getProprietaryDriver())
                except TypeError, errormsg:
                    # If there isn't it dies, so try again LP: #198269
                    self.driverlabel.setText(self.gfxcard.getGfxCardModel().getDriver())
            else:
                self.driverlabel.setText(self.gfxcard.getGfxCardModel().getDriver())
        else:
            self.setTitle(i18n("<Unknown>"))
            self.gfxcardlabel.setText(i18n("<Unknown>"))
            self.driverlabel.setText(i18n("<none>"))

        # Sync the screens and monitors.
        for i in range(len(self.gfxcard.getScreens())):
            screen = self.gfxcard.getScreens()[i]

            if screen.getMonitorModel() is None:
                monitor_name = i18n("<unknown>")
            else:
                monitor_name = QString(screen.getMonitorModel().getName())
            if screen.getMonitorAspect()==ModeLine.ASPECT_16_9:
                monitor_name.append(i18n(" (widescreen)"))
            self.monitorlabels[i].setText(monitor_name)

            if len(self.xsetup.getAllScreens())!=1:
                self.monitor_roles[i].setCurrentItem(
                    {XSetup.ROLE_PRIMARY: 0,
                    XSetup.ROLE_SECONDARY: 1,
                    XSetup.ROLE_UNUSED: 2}
                    [self.xsetup.getScreenRole(screen)])

    def slotGfxCardConfigureClicked(self):
        result = self.gfxcarddialog.do(self.gfxcard.getGfxCardModel(), \
            self.gfxcard.isProprietaryDriver(), self.gfxcard.getDetectedGfxCardModel(),
            self.gfxcard.getVideoRam())

        (new_card_model, new_proprietary_driver, new_video_ram) = result

        if new_card_model is self.gfxcard.getGfxCardModel() and \
                new_proprietary_driver==self.gfxcard.isProprietaryDriver() and \
                new_video_ram==self.gfxcard.getVideoRam():
            return
        self.gfxcard.setGfxCardModel(new_card_model)
        self.gfxcard.setProprietaryDriver(new_proprietary_driver)
        self.gfxcard.setVideoRam(new_video_ram)
        self._syncGUI()
        self.emit(PYSIGNAL("configChanged"), () )

    def slotMonitorConfigureClicked(self):
        screen_index = self.monitor_buttons.index(self.sender())
        screen_obj = self.gfxcard.getScreens()[screen_index]

        (new_monitor_model,new_aspect) = self.monitordialog.do(screen_obj.getMonitorModel(),
            screen_obj.getMonitorAspect(),
            self.xsetup.getGfxCards()[0].getScreens()[0] is screen_obj)

        screen_obj.setMonitorModel(new_monitor_model)
        screen_obj.setMonitorAspect(new_aspect)
        self._syncGUI()
        self.emit(PYSIGNAL("configChanged"), () )

    def slotRoleSelected(self,index):
        screen_index = self.monitor_roles.index(self.sender())        
        screen_obj = self.gfxcard.getScreens()[screen_index]
        self.xsetup.setScreenRole(screen_obj,[XSetup.ROLE_PRIMARY,XSetup.ROLE_SECONDARY,XSetup.ROLE_UNUSED][index])

        self._syncGUI()
        self.emit(PYSIGNAL("configChanged"), () )
