~ubuntu-branches/ubuntu/lucid/pitivi/lucid

« back to all changes in this revision

Viewing changes to pitivi/project.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2009-05-27 14:22:49 UTC
  • mfrom: (1.2.1 upstream) (3.1.13 experimental)
  • Revision ID: james.westby@ubuntu.com-20090527142249-tj0qnkc37320ylml
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
"""
26
26
 
27
27
import os.path
28
 
import gobject
29
28
import gst
30
 
from timeline.timeline import Timeline
31
 
from sourcelist import SourceList
32
 
from bin import SmartTimelineBin
33
 
from settings import ExportSettings
34
 
from configure import APPNAME
35
 
 
 
29
import traceback
36
30
from gettext import gettext as _
37
 
 
38
 
class Project(gobject.GObject):
39
 
    """ The base class for PiTiVi projects """
40
 
 
41
 
    __gsignals__ = {
42
 
        "settings-changed" : ( gobject.SIGNAL_RUN_LAST,
43
 
                               gobject.TYPE_NONE,
44
 
                               (  ))
 
31
from pitivi.log.loggable import Loggable
 
32
from pitivi.timeline.timeline import Timeline
 
33
from pitivi.timeline.track import Track
 
34
from pitivi.stream import AudioStream, VideoStream
 
35
from pitivi.pipeline import Pipeline
 
36
from pitivi.factories.timeline import TimelineSourceFactory
 
37
from pitivi.sourcelist import SourceList
 
38
from pitivi.settings import ExportSettings
 
39
from pitivi.configure import APPNAME
 
40
from pitivi.signalinterface import Signallable
 
41
from pitivi.action import ViewAction
 
42
from pitivi.formatters.format import save_project
 
43
 
 
44
class ProjectError(Exception):
 
45
    """Project error"""
 
46
    pass
 
47
 
 
48
class ProjectSaveLoadError(ProjectError):
 
49
    """Error while loading/saving project"""
 
50
    pass
 
51
 
 
52
class Project(Signallable, Loggable):
 
53
    """The base class for PiTiVi projects
 
54
 
 
55
    @ivar name: The name of the project
 
56
    @type name: C{str}
 
57
    @ivar description: A description of the project
 
58
    @type description: C{str}
 
59
    @ivar sources: The sources used by this project
 
60
    @type sources: L{SourceList}
 
61
    @ivar timeline: The timeline
 
62
    @type timeline: L{Timeline}
 
63
    @ivar pipeline: The timeline's pipeline
 
64
    @type pipeline: L{Pipeline}
 
65
    @ivar factory: The timeline factory
 
66
    @type factory: L{TimelineSourceFactory}
 
67
    @ivar format: The format under which the project is currently stored.
 
68
    @type format: L{FormatterClass}
 
69
    @ivar loaded: Whether the project is fully loaded or not.
 
70
    @type loaded: C{bool}
 
71
 
 
72
    Signals:
 
73
     - C{missing-plugins} : A plugin is missing for the given uri
 
74
     - C{loaded} : The project is now fully loaded.
 
75
    """
 
76
 
 
77
    __signals__ = {
 
78
        "settings-changed" : None,
 
79
        "missing-plugins": ["uri", "detail", "description"],
 
80
        "loaded" : None
45
81
        }
46
82
 
47
 
    def __init__(self, name="", uri=None):
 
83
    def __init__(self, name="", uri=None, **kwargs):
48
84
        """
49
85
        name : the name of the project
50
86
        uri : the uri of the project
51
87
        """
52
 
        gst.log("name:%s, uri:%s" % (name, uri))
53
 
        gobject.GObject.__init__(self)
 
88
        Loggable.__init__(self)
 
89
        self.log("name:%s, uri:%s", name, uri)
54
90
        self.name = name
55
91
        self.settings = None
56
92
        self.description = ""
57
93
        self.uri = uri
 
94
        self.urichanged = False
 
95
        self.format = None
58
96
        self.sources = SourceList(self)
59
 
        self.timeline = None
60
 
        self.timelinebin = None
 
97
 
61
98
        self.settingssigid = 0
62
 
        self._load()
63
 
 
64
 
    def _load(self):
65
 
        """ loads the project from a file """
66
 
        if self.timeline:
67
 
            return
68
 
        self.timeline = Timeline(self)
69
 
        if self.uri:
70
 
            raise NotImplementedError
71
 
 
72
 
    def getBin(self):
73
 
        """ returns the SmartTimelineBin of the project """
74
 
        if not self.timeline:
75
 
            return None
76
 
        if not self.timelinebin:
77
 
            self.timelinebin = SmartTimelineBin(self)
78
 
        return self.timelinebin
79
 
 
80
 
    def _save(self, filename):
81
 
        """ internal save function """
82
 
        # TODO
83
 
        pass
84
 
 
85
 
    def save(self):
86
 
        """ Saves the project to the project's current file """
87
 
        self._save(self.uri)
88
 
 
89
 
    def saveAs(self, filename):
90
 
        """ Saves the project to the given file name """
91
 
        self._save(filename)
92
 
 
93
 
    # setting methods
 
99
        self._dirty = False
 
100
 
 
101
        self.sources.connect('missing-plugins', self._sourceListMissingPluginsCb)
 
102
 
 
103
        self.timeline = Timeline()
 
104
 
 
105
        self.factory = TimelineSourceFactory(self.timeline)
 
106
        self.pipeline = Pipeline()
 
107
        self.view_action = ViewAction()
 
108
        self.view_action.addProducers(self.factory)
 
109
 
 
110
        # the loading formatter will set this accordingly
 
111
        self.loaded = True
 
112
 
 
113
    def release(self):
 
114
        self.pipeline.release()
 
115
        self.pipeline = None
 
116
 
 
117
    #{ Settings methods
 
118
 
94
119
    def _settingsChangedCb(self, unused_settings):
95
120
        self.emit('settings-changed')
96
121
 
100
125
        If no setting have been explicitely set, some smart settings will be
101
126
        chosen.
102
127
        """
 
128
        self.debug("self.settings %s", self.settings)
103
129
        return self.settings or self.getAutoSettings()
104
130
 
105
131
    def setSettings(self, settings):
107
133
        Sets the given settings as the project's settings.
108
134
        If settings is None, the current settings will be unset
109
135
        """
110
 
        gst.log("Setting %s as the project's settings" % settings)
 
136
        self.log("Setting %s as the project's settings", settings)
111
137
        if self.settings:
112
138
            self.settings.disconnect(self.settingssigid)
113
139
        self.settings = settings
114
140
        self.emit('settings-changed')
115
 
        self.settingssigid = self.settings.connect('settings-changed', self._settingsChangedCb)
 
141
        self.settingssigid = self.settings.connect('settings-changed',
 
142
            self._settingsChangedCb)
116
143
 
117
144
    def unsetSettings(self, unused_settings):
118
145
        """ Remove the currently configured settings."""
125
152
        If it has more than one, it will return the largest setting that suits
126
153
        all contained sources.
127
154
        """
 
155
        settings = ExportSettings()
128
156
        if not self.timeline:
129
 
            gst.warning("project doesn't have a timeline, returning default settings")
130
 
            return ExportSettings()
131
 
        settings = self.timeline.getAutoSettings()
132
 
        if not settings:
133
 
            gst.warning("Timeline didn't return any auto settings, return default settings")
134
 
            return ExportSettings()
135
 
 
136
 
        # add the encoders and muxer of the default settings
137
 
        curset = self.settings or ExportSettings()
138
 
        settings.vencoder = curset.vencoder
139
 
        settings.aencoder = curset.aencoder
140
 
        settings.muxer = curset.muxer
 
157
            self.warning("project doesn't have a timeline, returning default settings")
 
158
            return settings
 
159
 
 
160
        # FIXME: this is ugly, but rendering for now assumes at most one audio
 
161
        # and one video tracks
 
162
        have_audio = have_video = False
 
163
        for track in self.timeline.tracks:
 
164
            if isinstance(track.stream, VideoStream) and track.duration != 0:
 
165
                have_video = True
 
166
            elif isinstance(track.stream, AudioStream) and track.duration != 0:
 
167
                have_audio = True
 
168
 
 
169
        if not have_audio:
 
170
            settings.aencoder = None
 
171
 
 
172
        if not have_video:
 
173
            settings.vencoder = None
 
174
 
141
175
        return settings
142
176
 
143
 
 
144
 
def file_is_project(uri):
145
 
    """ returns True if the given uri is a PitiviProject file"""
146
 
    # TODO
147
 
    if not gst.uri_get_protocol(uri) == "file":
148
 
        raise NotImplementedError(_("%s doesn't yet handle non local projects") % APPNAME)
149
 
    return os.path.isfile(gst.uri_get_location(uri))
 
177
    #}
 
178
 
 
179
    def _sourceListMissingPluginsCb(self, source_list, uri, detail, description):
 
180
        return self.emit('missing-plugins', uri, detail, description)
 
181
 
 
182
    #{ Save and Load features
 
183
 
 
184
    def save(self, location=None, overwrite=False):
 
185
        """
 
186
        Save the project to the given location.
 
187
 
 
188
        @param location: The location to write to. If not specified, the
 
189
        current project location will be used (if set).
 
190
        @type location: C{URI}
 
191
        @param overwrite: Whether to overwrite existing location.
 
192
        @type overwrite: C{bool}
 
193
 
 
194
        @raises ProjectSaveLoadError: If no uri was provided and none was set
 
195
        previously.
 
196
        """
 
197
        self.log("saving...")
 
198
        location = location or self.uri
 
199
 
 
200
        if location == None:
 
201
            raise ProjectSaveLoadError("Location unknown")
 
202
 
 
203
        save_project(self, location or self.uri, self.format,
 
204
                     overwrite)
 
205
 
 
206
        self.uri = location
 
207
 
 
208
    def setModificationState(self, state):
 
209
        self._dirty = state
 
210
 
 
211
    def hasUnsavedModifications(self):
 
212
        return self._dirty
 
213
 
 
214
    def markLoaded(self):
 
215
        """
 
216
        Mark the project as loaded.
 
217
 
 
218
        Will emit the 'loaded' signal. Only meant to be used by
 
219
        L{Formatter}s.
 
220
        """
 
221
        self.loaded = True
 
222
        self.emit('loaded')