Framework to manage user projects in Pharo Smalltalk
[](https://img.shields.io/badge/license-MIT-blue.svg)
[](http://makeapullrequest.com)
[](http://www.repostatus.org/#active)
[](https://travis-ci.org/hernanmd/ProjectFramework)
[](https://ci.appveyor.com/project/hernanmd/projectframework)
[](https://coveralls.io/github/hernanmd/ProjectFramework?branch=master)
# Table of Contents
- [Description](#description)
- [Installation](#installation)
- [Install using Pharo](#install-using-pharo)
- [Install using CLI](#install-using-cli)
- [Baseline String](#baseline-string)
- [Usage](#usage)
- [Adding an Application and Project](#adding-application-and-project)
- [Configuring the Application](#configuring-the-application)
- [A session between an user and a project](#a-session-between-an-user-and-a-project)
- [Adding a Project Window](#adding-a-project-window)
- [Adding a Project Controller](#adding-a-project-controller)
- [Finite State Machine](#finite-state-machine)
- [Custom Application Settings](#custom-application-settings)
- [Translations](#translations)
- [Implementation notes](#implementation-note)
- [License](#license)
# Description
ProjectFramework is a MIT-licensed library for project management at application level with [Pharo Smalltalk](https://www.pharo.org). The ProjectFramework enables to build typical project-based desktop GUI applications, without reinventing the wheel for project behaviors such as Open, Save, Closing, setting properties, etc. For example, when an user close a project inside an application window, menu items such as close, properties, save, etc. should be disabled, and re-enabled again when a project is opened. This is managed by the ProjectFramework automatically. A Spec UI application can be automatically generated from templates with basic menu options in very few lines of code.
ProjectFramework is designed to create project-centric applications with minimal effort, and tries to be fairly agnostic regarding the choices of UI widget libraries, this means no widget toolkit dependent code.
# Installation
There are several ways to install the **ProjectFramework**. At minimum, you need a working Pharo virtual image installed in your system. Check the [Pharo website](http://www.pharo.org) for installation information regarding the Pharo Open-Source system. Once Pharo is launched you have the following installation options:
## Install using Pharo
```smalltalk
EpMonitor disableDuring: [
Metacello new
baseline: 'ProjectFramework';
repository: 'github://hernanmd/ProjectFramework/repository';
load ].
```
## Install using CLI
Install **ProjectFramework** from Command-Line Interface using [Pharo Install](https://github.com/hernanmd/pi):
```bash
pi install ProjectFramework
```
## Baseline String
If you want to add the ProjectFramework to your Metacello Baselines or Configurations, copy and paste the following expression:
```smalltalk
" ... "
spec
baseline: 'ProjectFramework'
with: [ spec repository: 'github://hernanmd/ProjectFramework/repository' ];
" ... "
```
## Libraries used
- [SState](https://github.com/mumez/SState) from Masashi Umezawa
- [i18N](https://github.com/astares/Pharo-I18N) from Torsten Bergmann
- [Spec](https://github.com/spec-framework)
- [Traits](http://scg.unibe.ch/research/traits)
- [file-dialog](https://github.com/peteruhnak/file-dialog) from Peter Uhnak
- [SpecUIAddOns](https://github.com/hernanmd/SpecUIAddOns)
- [Fuel](https://rmod.inria.fr/web/software/Fuel)
# Usage
## Adding an Application and Project
The ProjectFramework includes a class representing your whole Application. An Application is global to an image - only one application per image could be active at a time - and could contain a single active project or multiple projects. **PFProjectBase** is the basic core (abstract) class for user projects. A custom Project class could be created by inheriting from **PFProjectBase**. Such class will inherit basic project features, for example: setting or getting project author, adding or removing project users, adding or removing project owner(s), query project creation or modification dates, setting file name extension, and querying project history information. Every instantiated project must belong to an application, so the first thing to do is to create an application class:
An Application class should inherit from **PFProjectApplication**:s
```smalltalk
PFProjectApplication subclass: #MyApplicationClass
instanceVariableNames: ''
classVariableNames: ''
package: 'MyApplication-Core'
```
If there is just one subclass of **PFProjectApplication** in the image, then it will be automatically configured and used as the "current application class". Otherwise, you should set up the current application class using the global preferences, for example:
```smalltalk
PFProjectSettings currentApplicationClass: PFSample1ApplicationClass.
```
**PFProjectSettings** implements customization points in ProjectFramework, so that the Settings Framework might collect them and populate a setting browser with them.
The following snippet details how to add your own Project class:
```smalltalk
PFProjectBase subclass: #MyPFProject
instanceVariableNames: ''
classVariableNames: ''
package: 'MyApplication-Core'
```
## Configuring the Application
To link the Application with the Project, we need to add a method to MyApplicationClass in instance side:
```smalltalk
defaultProjectClass
" Private - See superimplementor's comment "
^ MyPFProject
```
You can also configure the application name in class side of MyApplicationClass:
```smalltalk
applicationName
" Answer a <String> with receiver's name "
^ 'My First Application'
```
If you want to customize your serialized project file extension, define this method:
```smalltalk
applicationExtension
" Answer a <String> with receiver's project file extension "
^ 'ext'
```
Before jumping to automatic UI generation, you might want to explore the basic message sends and core classes in the **ProjectFramework**.
## A session between an user and a project
An user (**PFProjectUser**) represents an user with projects and can instantiate multiple projects, however **only one project** will be the active project (#currentProject) at a time for the current application.
Projects are identified by name (**String**), and an user cannot have duplicated projects, this is projects with the same name. The following expressions show how to create an user with a project, and the type of operations which could be done:
Creating an user with a new project:
```smalltalk
| usr prj |
usr := PFProjectUser named: 'John Perez'.
prj := usr addNewProject: 'My First Project'.
```
Check actually everything was correctly configured:
```smalltalk
prj authorName. "'John Perez'"
prj projectName. "'My First Project'"
```
A project can be queried for typical project expected attributes:
```smalltalk
prj fileName. "'My First Project.fuelprj'"
prj creationDateAsString. "'2018-03-13 01:47:57'"
prj saveStatus. "false"
```
Projects can also have owners.
```smalltalk
prj hasOwner. "false"
```
And versioning is also supported:
```smalltalk
prj version: '1.0.0'.
prj versionString. "'1.0.0'"
```
Save the project to file and ask if it was actually saved:
```smalltalk
prj save.
prj saveStatus.
```
The file name is actually the project name, added with a default "fuelprj" extension (the extension **String** can be configured later):
```smalltalk
'My First Project.fuelprj' asFileReference exists. "true"
```
Currently the **ProjectFramework** serializes and materialize its projects using the [Fuel](https://rmod.inria.fr/web/software/Fuel) serialization library.
There are different ways to create projects, depending on specific scenarios. Creating and adding projects are two separate things. An user can create a project meaning only instantiating a new **PFProjectBase**, without adding it as part of its application projects. On the other hand, adding a project means creating the instance, and adding it to both the application and the collection of user projects.
Let's create another project:
```smalltalk
prj2 := usr createProject: 'My Second Project'.
```
Check that such project was not added to the user projects yet:
```smalltalk
usr hasProjectNamed: 'My Second Project'.
```
And then we can add it to the user projects:
```smalltalk
usr addProject: prj2.
````
> Note that previously we added a project passing its name, and now we use a **PFProjectBase** as parameter, the result is the same.
Finally re-check again if it was added correctly:
```smalltalk
usr hasProjectNamed: 'My Second Project'.
```
None of the previosuly sends set the created project as the current application project. That should be done separately using:
```smalltalk
prj setCurrentFor: usr.
```
## Adding a Project Window
The ProjectFramework has built-in support for several types of User-Interfaces. The differences between UI's are that they provide different layouts considering the features (or limitations) of available underlying widget library. This also provides an abstra