def __init__(self, task_data):
        QMainWindow.__init__(self, None, Qt.WindowTitleHint  | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint)

        self._task_data = task_data
        self.setWindowTitle("SimpleTaskManager 1.0.0-SNAPSHOT")
        self._table_dictionary = {}
        self._current_task = None
        self._current_row = None

        self.category_group = CategoryGroup(self._task_data)
        self.status_group = FilterGroup(self._task_data, self._task_data.STATUSES, "Status")
        self.priority_group = FilterGroup(self._task_data, self._task_data.PRIORITIES, "Priority")

        layout = QGridLayout()

        add_task = QPushButton("Add Task")

        self.task_table = QTableWidget()
        self.task_table.setToolTip("Double-click a row to edit the task.")
        self.task_table.setColumnCount(8)
        self.task_table.setHorizontalHeaderLabels(["Category", "Priority", "Task", "Status", "Entry Date", "Due Date", "Check List", "Exp. Effort"])
        self.task_table.setMinimumWidth(800)
        self.refresh_table(self._task_data)

        layout.addWidget(add_task, 0, 4)
        layout.addWidget(self.task_table, 1, 0, 1, 5)

        self.task_table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.task_table.customContextMenuRequested.connect(self.show_context_menu)

        add_task.clicked.connect(self.display_new_task_dialog)
        self.task_table.cellDoubleClicked.connect(self.display_edit_task_dialog)
        self.task_table.cellClicked.connect(self.display_checklist)

        section_layout = QHBoxLayout()
        section_layout.addLayout(self._build_leftside_layout())
        section_layout.addLayout(layout)
        self.filter_tasks()

        self.setMinimumWidth(800)
        self.setMinimumHeight(600)
        frame = QFrame()
        frame.setLayout(section_layout)
        self.setCentralWidget(frame)
        self.setFocus()
class TaskWindow(QMainWindow):
    def __init__(self, task_data):
        QMainWindow.__init__(self, None, Qt.WindowTitleHint  | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint)

        self._task_data = task_data
        self.setWindowTitle("SimpleTaskManager 1.0.0-SNAPSHOT")
        self._table_dictionary = {}
        self._current_task = None
        self._current_row = None

        self.category_group = CategoryGroup(self._task_data)
        self.status_group = FilterGroup(self._task_data, self._task_data.STATUSES, "Status")
        self.priority_group = FilterGroup(self._task_data, self._task_data.PRIORITIES, "Priority")

        layout = QGridLayout()

        add_task = QPushButton("Add Task")

        self.task_table = QTableWidget()
        self.task_table.setToolTip("Double-click a row to edit the task.")
        self.task_table.setColumnCount(8)
        self.task_table.setHorizontalHeaderLabels(["Category", "Priority", "Task", "Status", "Entry Date", "Due Date", "Check List", "Exp. Effort"])
        self.task_table.setMinimumWidth(800)
        self.refresh_table(self._task_data)

        layout.addWidget(add_task, 0, 4)
        layout.addWidget(self.task_table, 1, 0, 1, 5)

        self.task_table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.task_table.customContextMenuRequested.connect(self.show_context_menu)

        add_task.clicked.connect(self.display_new_task_dialog)
        self.task_table.cellDoubleClicked.connect(self.display_edit_task_dialog)
        self.task_table.cellClicked.connect(self.display_checklist)

        section_layout = QHBoxLayout()
        section_layout.addLayout(self._build_leftside_layout())
        section_layout.addLayout(layout)
        self.filter_tasks()

        self.setMinimumWidth(800)
        self.setMinimumHeight(600)
        frame = QFrame()
        frame.setLayout(section_layout)
        self.setCentralWidget(frame)
        self.setFocus()

    def show_context_menu(self, position):
        self._current_row = self.task_table.rowAt(position.y())
        self._current_task = self._table_dictionary[self._current_row]
        status = self._current_task.get_status().get_description()
        menu = QMenu(self)
        if status == "New":
            in_progress = QAction("Getting started", self)
            menu.addAction(in_progress)
            in_progress.triggered.connect(self.start_task)
        if status == "In Progress":
            complete = QAction("Finished !!!", self)
            menu.addAction(complete)
            complete.triggered.connect(self.finish_task)
        menu.addSeparator()
        cancelled = QAction("Not going to do it.", self)
        menu.addAction(cancelled)
        cancelled.triggered.connect(self.cancel_task)

        menu.popup(self.task_table.mapToGlobal(position))


    def start_task(self):
        status_by_name = self._task_data.get_status_by_name()
        in_progress = status_by_name["In Progress"]
        self._current_task.set_status(in_progress)
        self._task_data.save_task(self._current_task)
        self._update_row(self._current_task, self._current_row)
        self.filter_tasks()


    def finish_task(self):
        status_by_name = self._task_data.get_status_by_name()
        complete = status_by_name["Complete"]
        self._current_task.set_status(complete)
        self._task_data.save_task(self._current_task)
        self._update_row(self._current_task, self._current_row)
        self.filter_tasks()


    def cancel_task(self):
        status_by_name = self._task_data.get_status_by_name()
        cancelled = status_by_name["Cancelled"]
        self._current_task.set_status(cancelled)
        self._task_data.save_task(self._current_task)
        self._update_row(self._current_task, self._current_row)
        self.filter_tasks()


    def display_new_task_dialog(self):
        dialog = TaskEntryDialog(self._task_data, parent=self)
        if dialog.exec_():
            task = dialog.get_task()
            self._task_data.save_task(task)
            self.refresh_table(self._task_data)
            self.filter_tasks()


    def display_edit_task_dialog(self, row, column):
        task = self._table_dictionary[row]
        dialog = TaskEntryDialog(self._task_data, task, parent=self)
        if dialog.exec_():
            updated_task = dialog.get_task()
            #self._update_row(updated_task, row)
            self._task_data.save_task(task)
            self.refresh_table(self._task_data)
            self.filter_tasks()


    def _add_new_task(self, task):
        rows = self.task_table.rowCount()
        self.task_table.setRowCount(rows + 1)
        self._update_row(task, rows)

    def _create_table_item(self, text):
        item = QTableWidgetItem(text)
        item.setFlags(Qt.ItemIsEditable)
        item.setFlags(Qt.ItemIsEnabled)
        return item

    def _expected_effort_display(self, hours, minutes):
        return str(hours) + "h " + str(minutes) + "m";

    def _update_row(self, task, row):
        category_text = "" if task.get_category() is None else task.get_category().get_description()
        category = self._create_table_item(category_text)
        priority = self._create_table_item(task.get_priority().get_description())
        description = self._create_table_item(task.get_description())
        status = self._create_table_item(task.get_status().get_description())
        entrydate = self._create_table_item(task.get_entry_date().strftime("%Y-%m-%d"))
        duedate_text = "" if task.get_due_date() is None else task.get_due_date().strftime("%Y-%m-%d")
        duedate = self._create_table_item(duedate_text)
        item_text = " item" if task.get_checklist_count() == 1 else " items"
        checklist = self._create_table_item(str(task.get_checklist_count()) + item_text)
        expected_effort = self._create_table_item(self._expected_effort_display(
                                                  task.get_expected_hours(),
                                                  task.get_expected_minutes()))
        font = QFont(checklist.font())
        font.setUnderline(True)
        checklist.setFont(font)
        color = QColor(0,0,255)
        checklist.setTextColor(color)
        self.task_table.setItem(row, 0, category)
        self.task_table.setItem(row, 1, priority)
        self.task_table.setItem(row, 2, description)
        self.task_table.setItem(row, 3, status)
        self.task_table.setItem(row, 4, entrydate)
        self.task_table.setItem(row, 5, duedate)
        self.task_table.setItem(row, 6, checklist)
        self.task_table.setItem(row, 7, expected_effort)
        self.task_table.resizeColumnsToContents()
        if task.get_due_date() is not None:
            warning_color = self._assign_color(task)
            #TODO: Need to create a new category for this
            if  task.get_status().get_selected_by_default():
                category.setBackgroundColor(warning_color)
                priority.setBackgroundColor(warning_color)
                description.setBackgroundColor(warning_color)
                status.setBackgroundColor(warning_color)
                entrydate.setBackgroundColor(warning_color)
                duedate.setBackgroundColor(warning_color)
                checklist.setBackgroundColor(warning_color)
                expected_effort.setBackgroundColor(warning_color)
        self._table_dictionary[row] = task

    def _assign_color(self, task):
            day_difference = (task.get_due_date() - datetime.datetime.now().date()).days * 36
            alpha = 255 - day_difference
            if alpha < 0:
                alpha = 0
            if alpha > 255:
                alpha = 255
            yellow = 255 - alpha
            if task.get_due_date() < datetime.datetime.now().date():
                return QColor(255, 0, 0, 100)
            else:
                return QColor(75, 255, yellow, alpha)

    def _build_leftside_layout(self):

        top_align_layout = QVBoxLayout()
        control_layout = QGridLayout()
        self.category_group.filtered.connect(self.filter_tasks)
        control_layout.addWidget(self.category_group, 0, 0)
        self.status_group.filtered.connect(self.filter_tasks)
        control_layout.addWidget(self.status_group, 1, 0)
        self.priority_group.filtered.connect(self.filter_tasks)
        control_layout.addWidget(self.priority_group,2, 0)
        top_align_layout.addLayout(control_layout)
        top_align_layout.addStretch(1)
        return top_align_layout

    def filter_tasks(self):
        for i in range(self.task_table.rowCount()):
            task = self._table_dictionary[i]
            category_dictionary = self.category_group.get_control_dictionary()
            status_dictionary = self.status_group.get_control_dictionary()
            priority_dictionary = self.priority_group.get_control_dictionary()
            if task.get_status().get_id() in status_dictionary:
                status_display = status_dictionary[task.get_status().get_id()].isChecked()
            else:
                status_display = True
            priority_display = priority_dictionary[task.get_priority().get_id()].isChecked()
            if task.get_category().get_id() in category_dictionary:
                category_check = category_dictionary[task.get_category().get_id()]
                if category_check.isHidden() or not category_check.isChecked() or not status_display or not priority_display:
                    self.task_table.setRowHidden(i, True)
                else:
                    self.task_table.setRowHidden(i, False)

    def refresh_table(self, task_data):
        task_list = self._task_data.get_task_list()
        self._clear_table()
        for task in task_list:
            self._add_new_task(task)

    def _clear_table(self):
        while self.task_table.rowCount() > 0:
            self.task_table.removeRow(0)
        self._table_dictionary = {}


    def display_checklist(self, row, column):
        if column == 6:
            task = self._table_dictionary[row]
            checklist = CheckListDialog(self._task_data, task, row, parent=self)
            checklist.updated.connect(self.update_checklist_count)
            checklist.show()

    def update_checklist_count(self, row_id, count):
        table_item = self.task_table.item(row_id, 6)
        item_text = " item" if count == 1 else " items"
        table_item.setText(str(count) + " " + item_text)