{"id":15107746,"url":"https://github.com/cormas/projectframework","last_synced_at":"2025-10-23T02:31:32.784Z","repository":{"id":51330371,"uuid":"124332685","full_name":"cormas/ProjectFramework","owner":"cormas","description":"Framework to manage user projects in Pharo Smalltalk","archived":false,"fork":false,"pushed_at":"2023-10-04T16:25:40.000Z","size":749,"stargazers_count":6,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-30T17:12:21.977Z","etag":null,"topics":["framework","pharo","pharo-smalltalk","project-manager","smalltalk"],"latest_commit_sha":null,"homepage":null,"language":"Smalltalk","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cormas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-03-08T03:42:18.000Z","updated_at":"2023-02-24T15:19:23.000Z","dependencies_parsed_at":"2023-10-04T21:27:30.538Z","dependency_job_id":null,"html_url":"https://github.com/cormas/ProjectFramework","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cormas%2FProjectFramework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cormas%2FProjectFramework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cormas%2FProjectFramework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cormas%2FProjectFramework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cormas","download_url":"https://codeload.github.com/cormas/ProjectFramework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237769067,"owners_count":19363250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["framework","pharo","pharo-smalltalk","project-manager","smalltalk"],"created_at":"2024-09-25T21:41:23.314Z","updated_at":"2025-10-23T02:31:32.164Z","avatar_url":"https://github.com/cormas.png","language":"Smalltalk","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![license-badge](https://img.shields.io/badge/license-MIT-blue.svg)](https://img.shields.io/badge/license-MIT-blue.svg)\r\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\r\n[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active)\r\n[![Build Status](https://travis-ci.org/hernanmd/ProjectFramework.svg?branch=master)](https://travis-ci.org/hernanmd/ProjectFramework)\r\n[![Build status](https://ci.appveyor.com/api/projects/status/x265r8o52iirm9g2?svg=true)](https://ci.appveyor.com/project/hernanmd/projectframework)\r\n[![Coverage Status](https://coveralls.io/repos/github/hernanmd/ProjectFramework/badge.svg?branch=master)](https://coveralls.io/github/hernanmd/ProjectFramework?branch=master)\r\n\r\n# Table of Contents\r\n\r\n- [Description](#description)\r\n- [Installation](#installation)\r\n  - [Install using Pharo](#install-using-pharo)\r\n  - [Install using CLI](#install-using-cli)\r\n  - [Baseline String](#baseline-string)\r\n- [Usage](#usage)\r\n  - [Adding an Application and Project](#adding-application-and-project)\r\n  - [Configuring the Application](#configuring-the-application)\r\n  - [A session between an user and a project](#a-session-between-an-user-and-a-project)\r\n  - [Adding a Project Window](#adding-a-project-window)\r\n  - [Adding a Project Controller](#adding-a-project-controller)\r\n  - [Finite State Machine](#finite-state-machine)\r\n  - [Custom Application Settings](#custom-application-settings)\r\n  - [Translations](#translations)\r\n- [Implementation notes](#implementation-note)\r\n- [License](#license)\r\n\r\n\r\n# Description\r\n\r\nProjectFramework 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.\r\n\r\nProjectFramework 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.\r\n\r\n# Installation\r\n\r\nThere 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:\r\n\r\n## Install using Pharo\r\n\r\n```smalltalk\r\nEpMonitor disableDuring: [\r\n  Metacello new\t\r\n    baseline: 'ProjectFramework';\t\r\n    repository: 'github://hernanmd/ProjectFramework/repository';\t\r\n    load ].\r\n```\r\n\r\n## Install using CLI\r\n\r\nInstall **ProjectFramework** from Command-Line Interface using [Pharo Install](https://github.com/hernanmd/pi):\r\n\r\n```bash\r\npi install ProjectFramework\r\n```\r\n\r\n## Baseline String\r\n\r\nIf you want to add the ProjectFramework to your Metacello Baselines or Configurations, copy and paste the following expression:\r\n\r\n```smalltalk\r\n        \" ... \"\r\n        spec\r\n                baseline: 'ProjectFramework' \r\n                with: [ spec repository: 'github://hernanmd/ProjectFramework/repository' ];\r\n        \" ... \"\r\n```\r\n\r\n## Libraries used\r\n\r\n  - [SState](https://github.com/mumez/SState) from Masashi Umezawa\r\n  - [i18N](https://github.com/astares/Pharo-I18N) from Torsten Bergmann\r\n  - [Spec](https://github.com/spec-framework)\r\n  - [Traits](http://scg.unibe.ch/research/traits)\r\n  - [file-dialog](https://github.com/peteruhnak/file-dialog) from Peter Uhnak\r\n  - [SpecUIAddOns](https://github.com/hernanmd/SpecUIAddOns)\r\n  - [Fuel](https://rmod.inria.fr/web/software/Fuel)\r\n\r\n# Usage\r\n\r\n## Adding an Application and Project\r\n\r\nThe 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:\r\n\r\nAn Application class should inherit from **PFProjectApplication**:s\r\n\r\n```smalltalk\r\nPFProjectApplication subclass: #MyApplicationClass\r\n   \tinstanceVariableNames: ''\r\n   \tclassVariableNames: ''\r\n   \tpackage: 'MyApplication-Core'\r\n```\r\n\r\nIf 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:\r\n\r\n```smalltalk\r\nPFProjectSettings currentApplicationClass: PFSample1ApplicationClass.\r\n``` \r\n\r\n**PFProjectSettings** implements customization points in ProjectFramework, so that the Settings Framework might collect them and populate a setting browser with them.\r\n\r\n\r\nThe following snippet details how to add your own Project class:\r\n\r\n\r\n```smalltalk\r\nPFProjectBase subclass: #MyPFProject\r\n   \tinstanceVariableNames: ''\r\n   \tclassVariableNames: ''\r\n   \tpackage: 'MyApplication-Core'\r\n```\r\n\r\n## Configuring the Application\r\n\r\nTo link the Application with the Project, we need to add a method to MyApplicationClass in instance side:\r\n\r\n```smalltalk\r\ndefaultProjectClass\r\n\t\" Private - See superimplementor's comment \"\r\n\r\n\t^ MyPFProject\r\n```\r\n\r\nYou can also configure the application name in class side of MyApplicationClass:\r\n\r\n```smalltalk\r\napplicationName\r\n\t\" Answer a \u003cString\u003e with receiver's name \"\r\n\t\r\n\t^ 'My First Application'\r\n```\r\n\r\nIf you want to customize your serialized project file extension, define this method:\r\n\r\n```smalltalk\r\napplicationExtension\r\n\t\" Answer a \u003cString\u003e with receiver's project file extension \"\r\n\r\n\t^ 'ext'\r\n```\r\n\r\nBefore jumping to automatic UI generation, you might want to explore the basic message sends and core classes in the **ProjectFramework**.\r\n\r\n## A session between an user and a project\r\n\r\nAn 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. \r\n\r\nProjects 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:\r\n\r\nCreating an user with a new project:\r\n\r\n```smalltalk\r\n| usr prj |\r\n\r\nusr := PFProjectUser named: 'John Perez'.\r\nprj := usr addNewProject: 'My First Project'.\r\n```\r\n\r\nCheck actually everything was correctly configured:\r\n\r\n```smalltalk\r\nprj authorName.  \"'John Perez'\"\r\nprj projectName. \"'My First Project'\"\r\n```\r\n\r\nA project can be queried for typical project expected attributes:\r\n\r\n```smalltalk\r\nprj fileName. \"'My First Project.fuelprj'\"\r\nprj creationDateAsString. \"'2018-03-13 01:47:57'\"\r\nprj saveStatus.  \"false\"\r\n```\r\n\r\nProjects can also have owners.\r\n\r\n```smalltalk\r\nprj hasOwner.  \"false\"\r\n```\r\n\r\nAnd versioning is also supported:\r\n\r\n```smalltalk\r\nprj version: '1.0.0'.\r\nprj versionString. \"'1.0.0'\"\r\n```\r\n\r\nSave the project to file and ask if it was actually saved:\r\n\r\n```smalltalk\r\nprj save.\r\nprj saveStatus.\r\n```\r\n\r\nThe file name is actually the project name, added with a default \"fuelprj\" extension (the extension **String** can be configured later):\r\n\r\n```smalltalk\r\n'My First Project.fuelprj' asFileReference exists.  \"true\"\r\n```\r\n\r\nCurrently the **ProjectFramework** serializes and materialize its projects using the [Fuel](https://rmod.inria.fr/web/software/Fuel) serialization library.\r\n\r\nThere 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.\r\n\r\nLet's create another project:\r\n\r\n```smalltalk\r\nprj2 := usr createProject: 'My Second Project'.\r\n```\r\n\r\nCheck that such project was not added to the user projects yet: \r\n\r\n```smalltalk\r\nusr hasProjectNamed: 'My Second Project'.\r\n```\r\n\r\nAnd then we can add it to the user projects:\r\n\r\n```smalltalk\r\nusr addProject: prj2.\r\n````\r\n\u003e Note that previously we added a project passing its name, and now we use a **PFProjectBase** as parameter, the result is the same.\r\n\r\nFinally re-check again if it was added correctly: \r\n\r\n```smalltalk\r\nusr hasProjectNamed: 'My Second Project'.\r\n```\r\n\r\nNone of the previosuly sends set the created project as the current application project. That should be done separately using:\r\n\r\n```smalltalk\r\nprj setCurrentFor: usr.\r\n```\r\n\r\n## Adding a Project Window \r\n\r\nThe 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 abstraction layer for future widget toolkits or libraries (such as [Bloc](https://github.com/pharo-graphics/Bloc)).\r\n\r\nFirst we require a \"Window\" class:\r\n\r\n```smalltalk\r\nPFStandardProjectWindow subclass: #MyAppProjectWindow\r\n\tinstanceVariableNames: ''\r\n\tclassVariableNames: ''\r\n\tpackage: 'MyApplication-UI'\r\n```\r\n\r\nWe need to link your application with your project. Add the following class (we will talk about it in the next section about Adding a project controller):\r\n\r\n```smalltalk\r\nPFProjectManager subclass: #MyAppProjectManager\r\n\tinstanceVariableNames: ''\r\n\tclassVariableNames: ''\r\n\tpackage: 'MyApplication-UI'\r\n```\r\n\r\nThen add an instance method in MyAppProjectWindow:\r\n\r\n```smalltalk\r\ndefaultProjectManagerClass\r\n\r\n\t^ MyAppProjectManager\r\n```\r\n\r\nIf you want to close the Window after creating a project, add the following method: \r\n\r\n```smalltalk\r\ncloseAfterCreateProject\r\n   \t\" Answer \u003ctrue\u003e if receiver's window should close after creation of a project \"\r\n\r\n\t^ true\r\n```\r\n\r\nIf you want to inform the user of the current project, implement #defaultWindowTitle to answer a **String** and do not override the #title method.\r\n\r\nFrom now the link between application, and other artifacts are managed by a *Controller* object.\r\n\r\n## Adding a Project Controller\r\n\r\nThe project window is responsible to render the widgets and trigger to user events such as opening, saving or closing project files. However, to maintain a clear separation of responsibilities and cleaner interfaces, such additional features are implemented in a class acting as *Controller*, connecting the project model **MyPFProject** and the UI **MyAppProjectWindow**. The root class for project controllers is **PFProjectManager**. Currently provides the following features:\r\n\r\n  - Link the UI to application and project classes.\r\n  - Accessing translations through an application translator object.\r\n  - Code for serialization and materialization of project files.\r\n  - Exception handling for creation, opening and removing projects.\r\n  - Provides a Finite-State Machine protocol for events and actions.\r\n  - Recent projects management.\r\n\r\nImplement the following method in your controller:\r\n\r\n```smalltalk\r\ninitialize\r\n\t\" Private - See superimplementor's comment \"\r\n\r\n\tsuper initialize.\r\n\tself applicationClass: MyApplicationClass.\r\n\tself projectClass: MyAppProject.\r\n```\r\n\r\nYou may notice that we inherited the main application window from **PFStandardProjectWindow** class. Actually he ProjectFramework includes two library bindings to render the UI:\r\n\r\n### ProjectFrameworkSpec\r\n\r\nProjectFrameworkSpec classes inherits from **ComposableModel** (in Pharo 6.x) or **ComposablePresenter** (in Pharo 7.x) and uses the [SpecUIAddOns](https://github.com/hernanmd/SpecUIAddOns) package classes to provide a \"standard\" layout. The standard project window is based in the Spec **ApplicationWithToolbar** class. Alternatively, a \"Project Details\" with or without recent projects list layout is also available.\r\n\r\nHere is a screenshot of both layouts:\r\n\r\n#### Classic Layout\r\n\r\n![convertidor iso 11784 - senasa 754](https://user-images.githubusercontent.com/4825959/37262532-5fca39d8-2582-11e8-9a0a-c6c0e594a303.png)\r\n\r\nTo launch an example window, please evaluate:\r\n\r\n```smalltalk\r\nPFSample1StandardWindow open.\r\n````\r\n\r\nAlso to configure the application for the first time or re-initialize the translation tables.\r\n```smalltalk\r\nPFProjectSettings currentApplicationClass: PFSample1ApplicationClass.\r\nPFSample1ApplicationClass uniqueInstance translator: nil.\r\nPFSample1StandardWindow open.\r\n```\r\n\r\nTo use this layout, subclass the **PFStandardProjectWindow** as shown in the example above.\r\n\r\n#### Recent Projects Layout\r\n\r\nTo launch an example window, please evaluate:\r\n\r\n```smalltalk\r\nPFSample1RecentsWindow open\r\n````\r\n\r\n![rehhcg_1](https://user-images.githubusercontent.com/4825959/37262533-5ffe728e-2582-11e8-85b5-893b2df53171.png)\r\n\r\nTo use this layout, subclass the **PFProjectDetailsWindow**\r\n\r\n#### Recent and Details Layout\r\n\r\nTo launch an example window, please evaluate:\r\n\r\n```smalltalk\r\nPFSample1RecentsDetailsWindow open\r\n````\r\n\r\n### ProjectFrameworkMorphic\r\n\r\nThe docking project window is based in the **DockingBarMorph** class, and enables to use the ProjectFramework without Spec (or other higher-level library) dependency.\r\n\r\n![dockingpfwindow](https://user-images.githubusercontent.com/4825959/37263455-0a19abae-2587-11e8-9087-828cdfea3e2d.png)\r\n\r\n## Finite State Machine\r\n\r\nThe [SState](http://smalltalkhub.com/#!/~MasashiUmezawa/SState \"SState\") package provides a Finite State Machine (FSM) implementation. To manage common project events, actions and states the ProjectFramework configures an extremely simple FSM: Every project (subclass of **PFProjectBase**) contains, almost free of charge, a FSM with a predefined set of states and transitions:\r\n\r\n  - The actions, events and state names are configured in the #initializeFSM method.\r\n    - You can customize the FSM in the #initializeFSM method in your subclass of **PFProjectApplication**.\r\n    - To perform actions before entering the initial state of your application, for example when opening the main window, implement your own #updateStateInit in your subclass of **PFProjectManager**.\r\n  - The initial state is named *\"stateWaitNewOrOpen\"* which means, \"wait for a new project or open project\" event.\r\n  - Upon opening or creating a new project, the FSM transitions to a new state *\"stateWaitChangeOrClose\"*.\r\n  - When a project changes, the FSM performs another transition to *\"stateWaitSaveOrClose\"*.\r\n\r\nWhich translates in the following method (used if no FSM is specified):\r\n\r\n```smalltalk\r\ninitializeFSM\r\n\t\" Private - Initialize receiver's state machine \"\r\n\r\n\tself fsm: SsStateMachine new.\r\n\t(self fsm addStateNamed: #stateWaitNewOrOpen)\r\n    \tentryAction: [ self entryStateWaitNewOrOpen ];\r\n\t\texitAction: [ self exitStateWaitNewOrOpen ];\r\n\t\twhen: #actionOpened do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitChangeOrClose;\t\t\r\n\t\twhen: #actionNew do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitChangeOrClose.\r\n\t\t\r\n\t(self fsm addStateNamed: #stateWaitChangeOrClose)\r\n\t\tentryAction: [ self entryStateWaitChangeOrClose ];\r\n\t\texitAction: [ self exitStateWaitChangeOrClose ];\r\n\t\twhen: #actionSave do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitChangeOrClose;\r\n\t\twhen: #actionSaveAs do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitChangeOrClose;\t\t\t\r\n\t\twhen: #actionChange do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitSaveOrClose;\r\n\t\twhen: #actionClose do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitNewOrOpen.\r\n\r\n\t(self fsm addStateNamed: #stateWaitSaveOrClose)\r\n\t\tentryAction: [  self entryStateWaitSaveOrClose ];\r\n\t\texitAction: [  self exitStateWaitSaveOrClose ];\r\n\t\twhen: #actionClose do: [ : ctx : ev | ctx at: #pfTrans put: ev ] to: #stateWaitNewOrOpen.\r\n```\r\n\r\nAnd it can be visualized in the following transition graph:\r\n\r\n![fsm_simulator_-_2018-03-16_00 16 05](https://user-images.githubusercontent.com/4825959/37502697-0299434c-28b3-11e8-8b1c-d29ce44b03da.png)\r\n\r\nTo define your own FSM, specialize the #initializeFSM method in your **PFProjectManager** subclass (**MyAppProjectManager**). You can access the FSM through the #fsm getter.\r\n\r\nThe following example method contains how FSM events could be triggered in user's code:\r\n\r\n```smalltalk\r\ncreateNewProject\r\n\t\" Request a project name and answer a new project if valid name is supplied \"\r\n\t\r\n\t| answer |\r\n\r\n\t(answer := self requestMessage: self translator tNewProjectName) isEmptyOrNil \r\n\t\tifFalse: [ \r\n\t\t\tself createAppProject: answer.\r\n\t\t\tself fsm handleEvent: #actionNew  ]\r\n\t\tifTrue: [ self informMessage: self translator tNewProjectEmptyName ].\r\n```\r\n\r\n## Custom Application Settings\r\n\r\nThe ProjectFramework provides also a class **PFProjectSettingsPharo** (using the Settings Framework of Pharo) to manage configuration of application and project.\r\n\r\n![pfsettingswindow](https://user-images.githubusercontent.com/4825959/37263696-0dfaa75e-2588-11e8-8468-773badd65a8a.png)\r\n\r\nTo open a settings window for the sample application, please evaluate: \r\n\r\n```smalltalk\r\nPFSample1ProjectSettings openSettings.\r\n```\r\n\r\nTo use this feature, subclass **PFProjectSettingsPharo** and add the following methods in class side:\r\n\r\n```smalltalk\r\napplicationClass\r\n\t\" Private - See superimplementor's comment \"\r\n\r\n\t^ PFSample1ApplicationClass  \r\n```\r\n\r\nYou will have to create a pragma keyword which you will use in your specific methods with settings code:\r\n\r\n```smalltalk\r\nprojectFrameworkPragmaKeywords\r\n\r\n\t^ Array with: 'projectSample1Settings'\r\n```\r\n\r\nFor example a setting to configure the user name of the Application:\r\n\r\n```smalltalk\r\nusernameSettingsOn: aBuilder\r\n\t\u003cprojectSample1Settings\u003e\r\n\r\n\t(aBuilder setting: #usernameSetting)\r\n\t\ttarget: self;\r\n\t\tdescription: 'Set the user name';\r\n\t\tlabel: 'Username';\r\n\t\tparent: #projectSettings\r\n```\r\n\r\n\r\n## Translations\r\n\r\nThe Project Framework currently uses the [i18N package](http://smalltalkhub.com/#!/~TorstenBergmann/I18N) to add translation support to menu items and messages. The abstract class to check for implementing i18N to your application is **PFTranslator**. Translation is defined per-application, and you should subclass **PFTranslator** for your application to add custom translations.\r\n\r\nThe current default **PFTranslator** adds two catalogs with related project operations. One catalog for english (see #addTranslationsForEN) and another one for spanish (#addTranslationsForES).\r\n\r\nTo set the default language for your application, define a #defaultTranslatorClass method in your application class (instance side):\r\n\r\n\r\n```smalltalk\r\ndefaultTranslatorClass\r\n\t\" Answer the default translation class for the receiver \"\r\n\r\n\t^ PFTranslator\r\n```\r\n\r\n\u003e Note: You can also completely replace the underlying translation library by replacing with another class from other available library such as [GetText](http://smalltalkhub.com/#!/~TorstenBergmann/Gettext).\r\n\r\nand a method to specify the default language if you want other than english:\r\n\r\n```smalltalk\r\ndefaultLanguageCode\r\n\t\" Answer a language code \u003cSymbol\u003e to set the default project language \"\r\n\t\r\n\t^ #ES\r\n```\r\n\r\nSpecialize the #initialize method in your **PFTranslator** subclass to add more languages to your application, for example:\r\n\r\n```smalltalk\r\ninitialize\r\n\t\" Private - Initialize the receiver's translation maps \"\r\n\r\n\tsuper initialize.\r\n\tself addTranslationsForFR.\r\n```\r\n\r\n# Implementation notes\r\n\r\n- Recent project behavior is implemented via Traits, this means that if you implement your own UI you could import the Trait as shown in the following expression:\r\n\r\n```smalltalk\r\nMyComposablePresenter subclass: #MyCustomAppWindow\r\n\tuses: TPFRecents\r\n\tinstanceVariableNames: 'projectManager'\r\n\tclassVariableNames: ''\r\n\tpackage: 'ProjectFrameworkSpec-Layouts'\r\n```\r\n\r\n- The ProjectFramework installs and set as default the native file dialogs developed by Peter Uhnak. If you want to switch back to the Morphic dialogs (however, the open file dialog will be unable to filter files by extension), please evaluate:\r\n\r\n```smalltalk\r\nMorphicUIManager new beDefault\r\n```\r\n\r\n\r\n# Contribute\r\n\r\n**Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)\r\n\r\nIf you have discovered a bug or have a feature suggestion, feel free to create an issue on Github.\r\nIf you have any suggestions for how this package could be improved, please get in touch or suggest an improvement using the GitHub issues page.\r\nIf you'd like to make some changes yourself, see the following:    \r\n\r\n  - Fork this repository to your own GitHub account and then clone it to your local device\r\n  - Do some modifications\r\n  - Test.\r\n  - Add \u003cyour GitHub username\u003e to add yourself as author below.\r\n  - Finally, submit a pull request with your changes!\r\n  - This project follows the [all-contributors specification](https://github.com/kentcdodds/all-contributors). Contributions of any kind are welcome!\r\n\r\n# License\r\n\t\r\nThis software is licensed under the MIT License.\r\n\r\nCopyright Hernán Morales Durand, 2018-2022\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n\r\n# Authors\r\n\r\nHernán Morales Durand\r\n\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcormas%2Fprojectframework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcormas%2Fprojectframework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcormas%2Fprojectframework/lists"}