Processes.py 11.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# -*- coding: utf-8 -*-
"""
$Id$

Copyright 2011 Lars Kruse <devel@sumpfralle.de>

This file is part of PyCAM.

PyCAM 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 of the License, or
(at your option) any later version.

PyCAM 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 PyCAM.  If not, see <http://www.gnu.org/licenses/>.
"""

import pycam.Plugins
Lars Kruse's avatar
Lars Kruse committed
24
from pycam.Utils import get_non_conflicting_name
25 26 27 28


class Processes(pycam.Plugins.ListPluginBase):

29
    DEPENDS = ["ParameterGroupManager"]
30
    CATEGORIES = ["Process"]
31 32 33
    UI_FILE = "processes.ui"

    def setup(self):
34
        self.core.set("processes", self)
35 36 37 38 39
        if self.gui:
            import gtk
            self._gtk = gtk
            process_frame = self.gui.get_object("ProcessBox")
            process_frame.unparent()
40
            self._gtk_handlers = []
41
            self.core.register_ui("main", "Processes", process_frame, weight=20)
42
            self._modelview = self.gui.get_object("ProcessEditorTable")
43 44 45
            self.set_gtk_modelview(self._modelview)
            self.register_model_update(lambda:
                    self.core.emit_event("process-list-changed"))
46 47 48
            for action, obj_name in ((self.ACTION_UP, "ProcessMoveUp"),
                    (self.ACTION_DOWN, "ProcessMoveDown"),
                    (self.ACTION_DELETE, "ProcessDelete")):
49
                self.register_list_action_button(action,
50
                        self.gui.get_object(obj_name))
51 52
            self._gtk_handlers.append((self.gui.get_object("ProcessNew"),
                    "clicked", self._process_new))
53 54 55 56 57 58 59
            # parameters
            parameters_box = self.gui.get_object("ProcessParametersBox")
            def clear_parameter_widgets():
                parameters_box.foreach(
                        lambda widget: parameters_box.remove(widget))
            def add_parameter_widget(item, name):
                # create a frame with an align and the item inside
60 61
                if item.get_parent():
                    item.unparent()
62 63 64 65 66 67
                frame_label = gtk.Label()
                frame_label.set_markup("<b>%s</b>" % name)
                frame = gtk.Frame()
                frame.set_label_widget(frame_label)
                align = gtk.Alignment()
                frame.add(align)
68
                align.set_padding(0, 3, 12, 3)
69 70 71 72 73
                align.add(item)
                frame.show_all()
                parameters_box.pack_start(frame, expand=False)
            self.core.register_ui_section("process_parameters",
                    add_parameter_widget, clear_parameter_widgets)
74 75 76 77
            self.core.get("register_parameter_group")("process",
                    changed_set_event="process-strategy-changed",
                    changed_set_list_event="process-strategy-list-changed",
                    get_current_set_func=self._get_strategy)
78
            self.parameter_widget = pycam.Gui.ControlsGTK.ParameterSection()
79
            self.core.register_ui_section("process_path_parameters",
80 81
                    self.parameter_widget.add_widget,
                    self.parameter_widget.clear_widgets)
82
            self.core.register_ui("process_parameters", "Path parameters",
Lars Kruse's avatar
Lars Kruse committed
83
                    self.parameter_widget.get_widget(), weight=10)
84 85
            self._gtk_handlers.append((self._modelview.get_selection(),
                    "changed", "process-selection-changed"))
86 87
            self._gtk_handlers.append((self.gui.get_object("NameCell"),
                    "edited", self._edit_process_name))
88 89
            self._treemodel = self.gui.get_object("ProcessList")
            self._treemodel.clear()
90 91 92 93
            self._gtk_handlers.append((self.gui.get_object("StrategySelector"),
                    "changed", "process-strategy-changed"))
            self._event_handlers = (
                    ("process-strategy-list-changed", self._update_widgets),
94
                    ("process-list-changed", self._trigger_table_update),
95 96 97 98 99
                    ("process-selection-changed", self._process_switch),
                    ("process-changed", self._store_process_settings),
                    ("process-strategy-changed", self._store_process_settings))
            self.register_gtk_handlers(self._gtk_handlers)
            self.register_event_handlers(self._event_handlers)
100
        self.register_state_item("processes", self)
101 102
        self.core.register_namespace("processes",
                pycam.Plugins.get_filter(self))
103 104 105
        return True

    def teardown(self):
106
        self.clear_state_items()
107
        self.core.unregister_namespace("processes")
108 109
        if self.gui:
            self.core.unregister_ui("main", self.gui.get_object("ProcessBox"))
110 111
            self.core.unregister_ui_section("process_path_parameters")
            self.core.unregister_ui("process_parameters",
Lars Kruse's avatar
Lars Kruse committed
112
                    self.parameter_widget.get_widget())
113
            self.core.unregister_ui_section("process_parameters")
114 115
            self.unregister_gtk_handlers(self._gtk_handlers)
            self.unregister_event_handlers(self._event_handlers)
116
        self.core.set("processes", None)
117 118
        while len(self) > 0:
            self.pop()
119 120 121
        return True

    def _render_process_description(self, column, cell, model, m_iter):
122
        process = self.get_by_path(model.get_path(m_iter))
123
        # TODO: describe the strategy
124
        text = "TODO"
125 126
        cell.set_property("text", text)

127
    def _render_process_name(self, column, cell, model, m_iter):
128 129
        process = self.get_by_path(model.get_path(m_iter))
        cell.set_property("text", process["name"])
130

131
    def _edit_process_name(self, cell, path, new_text):
132 133
        process = self.get_by_path(path)
        if process and (new_text != process["name"]) and new_text:
134
            process["name"] = new_text
135

136
    def _trigger_table_update(self):
137 138 139 140 141
        self.gui.get_object("NameColumn").set_cell_data_func(
                self.gui.get_object("NameCell"), self._render_process_name)
        self.gui.get_object("DescriptionColumn").set_cell_data_func(
                self.gui.get_object("DescriptionCell"),
                self._render_process_description)
142 143

    def _update_widgets(self):
144
        selected = self._get_strategy()
145 146
        model = self.gui.get_object("StrategyModel")
        model.clear()
147 148
        strategies = list(self.core.get("get_parameter_sets")("process").values())
        strategies.sort(key=lambda item: item["weight"])
149 150 151 152 153 154 155 156 157 158 159 160 161
        for strategy in strategies:
            model.append((strategy["label"], strategy["name"]))
        # check if any on the processes became obsolete due to a missing plugin
        removal = []
        strat_names = [strat["name"] for strat in strategies]
        for index, process in enumerate(self):
            if not process["strategy"] in strat_names:
                removal.append(index)
        removal.reverse()
        for index in removal:
            self.pop(index)
        # show "new" only if a strategy is available
        self.gui.get_object("ProcessNew").set_sensitive(len(model) > 0)
162 163 164 165 166
        selector_box = self.gui.get_object("ProcessSelectorBox")
        if len(model) < 2:
            selector_box.hide()
        else:
            selector_box.show()
167 168
        if selected:
            self.select_strategy(selected["name"])
169 170

    def _get_strategy(self, name=None):
171
        strategies = self.core.get("get_parameter_sets")("process")
172 173 174
        if name is None:
            # find the currently selected one
            selector = self.gui.get_object("StrategySelector")
175
            model = selector.get_model()
176 177 178 179 180 181
            index = selector.get_active()
            if index < 0:
                return None
            strategy_name = model[index][1]
        else:
            strategy_name = name
182 183
        if strategy_name in strategies:
            return strategies[strategy_name]
184 185 186 187 188
        else:
            return None

    def select_strategy(self, name):
        selector = self.gui.get_object("StrategySelector")
189
        for index, row in enumerate(selector.get_model()):
190 191 192 193 194 195
            if row[1] == name:
                selector.set_active(index)
                break
        else:
            selector.set_active(-1)

196
    def _store_process_settings(self):
197 198 199 200 201
        process = self.get_selected()
        control_box = self.gui.get_object("ProcessSettingsControlsBox")
        strategy = self._get_strategy()
        if process is None or strategy is None:
            control_box.hide()
202
        else:
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
            # Check if any of the relevant controls are still at their default
            # values for this process type. These values are overridden by the
            # default value of the new (changed) process type.
            # E.g. this changes the "overlap" value from 10 to 60 when
            # switching from slicing to surfacing.
            if process["strategy"] and process["strategy"] in \
                    self.core.get("get_parameter_sets")("process"):
                old_strategy = self.core.get("get_parameter_sets")("process")[process["strategy"]]
                if process["strategy"] != strategy["name"]:
                    changes = {}
                    common_keys = [key for key in old_strategy["parameters"] \
                            if key in strategy["parameters"]]
                    for key in common_keys:
                        if process["parameters"][key] == \
                                old_strategy["parameters"][key]:
                            changes[key] = strategy["parameters"][key]
                        self.core.get("set_parameter_values")("process", changes)
220 221
            process["strategy"] = strategy["name"]
            parameters = process["parameters"]
222
            parameters.update(self.core.get("get_parameter_values")("process"))
223 224
            control_box.show()
            self._trigger_table_update()
225

226
    def _process_switch(self, widget=None, data=None):
227 228 229 230 231
        process = self.get_selected()
        control_box = self.gui.get_object("ProcessSettingsControlsBox")
        if not process:
            control_box.hide()
        else:
232
            self.core.block_event("process-changed")
233
            self.core.block_event("process-strategy-changed")
234 235 236
            strategy_name = process["strategy"]
            self.select_strategy(strategy_name)
            strategy = self._get_strategy(strategy_name)
237
            self.core.get("set_parameter_values")("process", process["parameters"])
238
            control_box.show()
239
            self.core.unblock_event("process-strategy-changed")
240
            self.core.unblock_event("process-changed")
241
            self.core.emit_event("process-strategy-changed")
242 243
        
    def _process_new(self, *args):
244 245 246
        strategies = self.core.get("get_parameter_sets")("process").values()
        strategies.sort(key=lambda item: item["weight"])
        strategy = strategies[0]
Lars Kruse's avatar
Lars Kruse committed
247 248
        name = get_non_conflicting_name("Process #%d",
                [process["name"] for process in self])
249
        new_process = ProcessEntity({"strategy": strategy["name"],
250
                "parameters": strategy["parameters"].copy(),
Lars Kruse's avatar
Lars Kruse committed
251
                "name": name})
252 253 254
        self.append(new_process)
        self.select(new_process)

255 256 257 258 259 260

class ProcessEntity(pycam.Plugins.ObjectWithAttributes):

    def __init__(self, parameters):
        super(ProcessEntity, self).__init__("process", parameters)