Class: Ruber::AbstractProject
- Includes:
- SettingsContainer
- Defined in:
- lib/ruber/project.rb
Overview
Base class for all projects. It must be sublcassed to be used.
It has two main functionalities
-
store configuration options specific to each project (called project options), and read/write them to file, allow access to them and provide a way to configure them
-
store the projects extensions relative to this projects and allow access to them.
Project option management is almost all done by the included SettingsContainer module. The backend may be choose by subclasses, with the only restriction that it should provide a file
method returning the name of the file associated with it.
Subclasses must reimplement the :scope
method, which should return :global
if the project is a global one (that is a project managed by the ProjectList
) component or :document
if the project is associated with a single document.
A project can be in two states: active and inactive, depending on whether the user chose it as active project or not. Signals are emitted when the state changes. Note: there can be at most one active project at any given time.
Signals
option_changed(QString, QString)
Signal emitted when the value of an option changes. The two parameters are the group and the name of the option, converted to strings. You’ll have to convert them back to symbols if you want to use them to access the option’s value
closing(QObject*)
Signal emitted when the project is about to close The argument is the project itself. This is mostly used by project extensions which need to do some cleanup. They shouldn’t use it to store settings or similar, as there’s the save_settings
method for that.
saving()
Signal emitted just before the project is saved to file. This can be used by extensions to write their options to the project.
Direct Known Subclasses
Defined Under Namespace
Classes: InvalidProjectFile
Instance Attribute Summary collapse
-
#project_file ⇒ Object
readonly
The absolute path of the project file.
-
#project_name ⇒ Object
readonly
A string containing the name of the project.
Instance Method Summary collapse
-
#[]=(group, name, value) ⇒ Object
Override of SettingsContainer#[]= which after changing the value of the option, emits the
option_changed(QString, QString)
message if the value of the option changed (according to eql?). -
#add_extension(name, ext) ⇒ Object
Adds the project extension ext to the project, under the name name.
-
#close(save = true) ⇒ Boolean
Closes the project.
-
#each_extension ⇒ Object
If called with a block, calls it for each extension passing the extension name and the extension object itself as argument.
-
#extension(name) ⇒ Object
(also: #project_extension)
Returns the project extension with name name.
-
#extensions ⇒ Object
(also: #project_extensions)
Returns a hash having the extension names as keys and the extension objects as values.
-
#files ⇒ Object
Returns an array containing the name of the files belonging to the project.
-
#finalize ⇒ nil
Registers each component with the project.
-
#has_extension?(name) ⇒ Boolean
Returns true if the project contains an extension corresponding to the name
:name
and false otherwise. -
#initialize(parent, backend, name = nil) ⇒ AbstractProject
constructor
Creates a new Project.
-
#match_rule?(obj) ⇒ Boolean
Tells whether the project matches the rule specified in the object obj.
-
#method_missing(name, *args, &blk) ⇒ Object
Returns the project extension with name name.
-
#project_directory ⇒ Object
(also: #project_dir)
Returns the absolute path of project directory, that is the directory where the project file lies.
- #query_close ⇒ Object
-
#remove_extension(name) ⇒ Object
Removes the project extension with name name.
- #save ⇒ Object
-
#scope ⇒ Object
Returns the scope of the project (currently it must be either
:global
ordocument
). -
#write ⇒ Object
Override of
SettingsContainer#write
which emits thesettings_changed
signal after writing the settings to file.
Methods included from SettingsContainer
#[], #add_setting, #add_widget, #default, #dialog, #has_setting?, #relative_path?, #remove_setting, #remove_widget
Constructor Details
#initialize(parent, backend, name = nil) ⇒ AbstractProject
Creates a new Project. parent is the projects parent object (derived from Qt::Object
); file is the name of the project file, which may already exist or not, while name is the name of the project. name can only be specified if the project file doesn’t exist, otherwise ArgumentError
will be raised.
The project file, if existing, must follow the format described in the documentation for YamlSettingsBackend and must contain a :project_name
entry under the :general
group, otherwise it will be considered invalid. In this case, InvalidProjectFile will be raised.
The new project asks each component to register itself with it, so that project options, project widgets (widgets to be shown in the project’s configuration dialog) and project extensions are added. It also connects to the component_loaded
and unloading_component
signals of the component manager. The first allow each newly loaded plugin to register itself with the project, while the second allows any unloading plugin to unregister itself.
When the project is created, it’s not active.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/ruber/project.rb', line 112 def initialize parent, backend, name = nil super(parent) @active = false @project_file = backend.file setup_container backend, project_dir @dialog_class = ProjectDialog self.dialog_title = 'Configure Project' add_option OpenStruct.new(:group => :general, :name => :project_name, :default => nil) @project_name = self[:general, :project_name] if @project_name and name raise ArgumentError, "You can't specify a file name for an already existing project" elsif name self[:general, :project_name] = name @project_name = name elsif !@project_name and File.exist? @project_file raise InvalidProjectFile, "The project file #{@project_file} isn't invalid because it doesn't contain a project name entry" elsif !name and !File.exist? @project_file raise InvalidProjectFile, "You need to specify a project name for a new project" end @project_extensions = {} Ruber[:components].named_connect(SIGNAL('component_loaded(QObject*)'), "register_component_with_project #{object_id}"){|c| c.register_with_project self} Ruber[:components].named_connect(SIGNAL('unloading_component(QObject*)'), "remove_component_from_project #{object_id}"){|c| c.remove_from_project self} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &blk) ⇒ Object
Returns the project extension with name name. If a project extension with that name doesn’t exist, or if args is not empty, ArgumentError
is raised.
256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/ruber/project.rb', line 256 def method_missing name, *args, &blk begin super rescue NoMethodError, NameError, TypeError, ArgumentError => e if e.is_a? ArgumentError puts e. puts e.backtrace.join("\n") puts "Method name: #{name}" puts "Arguments: #{args.empty? ? '[]' : args.join( ', ')}" end raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" unless args.empty? @project_extensions[name] || super end end |
Instance Attribute Details
#project_file ⇒ Object (readonly)
The absolute path of the project file
90 91 92 |
# File 'lib/ruber/project.rb', line 90 def project_file @project_file end |
#project_name ⇒ Object (readonly)
A string containing the name of the project
85 86 87 |
# File 'lib/ruber/project.rb', line 85 def project_name @project_name end |
Instance Method Details
#[]=(group, name, value) ⇒ Object
Override of SettingsContainer#[]= which after changing the value of the option, emits the option_changed(QString, QString)
message if the value of the option changed (according to eql?).
188 189 190 191 192 |
# File 'lib/ruber/project.rb', line 188 def []= group, name, value old = @options[[group, name]] super emit option_changed group.to_s, name.to_s unless old.eql? value end |
#add_extension(name, ext) ⇒ Object
Adds the project extension ext to the project, under the name name. If an extension is already stored under that name, ArgumentError
is raised.
166 167 168 169 170 171 |
# File 'lib/ruber/project.rb', line 166 def add_extension name, ext if @project_extensions[name] raise ArgumentError, "An extension called '#{name}' already exists" end @project_extensions[name] = ext end |
#close(save = true) ⇒ Boolean
Closes the project
According to the save parameter, the project may save itself and its extensions' settings or not. In the first case, extensions may stop the project from closing by having their @query_close@ method return false. If save is false, nothing will be saved and the closing can’t be interrupted.
Before closing the project, the #closing signal is emitted. After that, all extensions will be removed (calling their @remove_from_project@ method if they have one).
310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/ruber/project.rb', line 310 def close save = true if save return false unless query_close return false unless self.save end emit closing(self) @project_extensions.each_key{|k| remove_extension k} Ruber[:components].named_disconnect "remove_component_from_project #{object_id}" Ruber[:components].named_disconnect "register_component_with_project #{object_id}" true end |
#each_extension ⇒ Object
If called with a block, calls it for each extension passing the extension name and the extension object itself as argument. If called without a block, returns an Enumerator
whose each
method works as explained above
207 208 209 210 211 212 |
# File 'lib/ruber/project.rb', line 207 def each_extension if block_given? @project_extensions.each_pair{|name, ext| yield name, ext} else self.to_enum(:each_extension) end end |
#extension(name) ⇒ Object Also known as: project_extension
Returns the project extension with name name.
197 198 199 |
# File 'lib/ruber/project.rb', line 197 def extension name @project_extensions[name] end |
#extensions ⇒ Object Also known as: project_extensions
Returns a hash having the extension names as keys and the extension objects as values.
Note: modifiying the hash doesn’t change the internal list of extensions
220 221 222 |
# File 'lib/ruber/project.rb', line 220 def extensions @project_extensions.dup end |
#files ⇒ Object
Returns an array containing the name of the files belonging to the project.
This method should be reimplemented in derived classes to return the actual list of files. The base class’s version always returns an empty array.
248 249 250 |
# File 'lib/ruber/project.rb', line 248 def files [] end |
#finalize ⇒ nil
This method has nothing to do with finalizers
Registers each component with the project
This is done in #initialize because, at least for DocumentProject, the extensions may try to access the project (directly or not) before it has fully been created.
This method should only be called from the object calling new
338 339 340 341 |
# File 'lib/ruber/project.rb', line 338 def finalize Ruber[:components].each_component{|c| c.register_with_project self} nil end |
#has_extension?(name) ⇒ Boolean
Returns true if the project contains an extension corresponding to the name :name
and false otherwise
229 230 231 |
# File 'lib/ruber/project.rb', line 229 def has_extension? name @project_extensions.has_key? name end |
#match_rule?(obj) ⇒ Boolean
Tells whether the project matches the rule specified in the object obj. obj is an object with at least the following methods:
-
scope
-
mimetype
-
file_extension
This implementation returns true if obj.scope
includes the value returned by self.scope
(using this method requires subclassing AbstractProject, since AbstractProject#scope
raises an exception). Subclasses may override this method to introduce other conditions. However, they’ll most likely always want to call the base class implementation.
158 159 160 |
# File 'lib/ruber/project.rb', line 158 def match_rule? obj obj.scope.include? self.scope end |
#project_directory ⇒ Object Also known as: project_dir
Returns the absolute path of project directory, that is the directory where the project file lies.
237 238 239 |
# File 'lib/ruber/project.rb', line 237 def project_directory File.dirname(@project_file) end |
#query_close ⇒ Object
322 323 324 325 |
# File 'lib/ruber/project.rb', line 322 def query_close @project_extensions.each_value{|v| return false unless v.query_close} true end |
#remove_extension(name) ⇒ Object
Removes the project extension with name name. If an extension with that name doesn’t exist, nothing is done.
177 178 179 180 181 |
# File 'lib/ruber/project.rb', line 177 def remove_extension name ext = @project_extensions[name] ext.remove_from_project if ext.respond_to? :remove_from_project @project_extensions.delete name end |
#save ⇒ Object
271 272 273 274 275 276 277 278 279 280 |
# File 'lib/ruber/project.rb', line 271 def save emit saving @project_extensions.each_value{|v| v.save_settings} begin write true rescue Exception false end end |
#scope ⇒ Object
Returns the scope of the project (currently it must be either :global
or document
).
This method must be overridden in derived classes, as it only raises NoMethodError
141 142 143 |
# File 'lib/ruber/project.rb', line 141 def scope raise NoMethodError, "Undefined method `scope' for #{self}:#{self.class}" end |
#write ⇒ Object
Override of SettingsContainer#write
which emits the settings_changed
signal after writing the settings to file
286 287 288 289 |
# File 'lib/ruber/project.rb', line 286 def write super emit settings_changed end |