Grafoscopio/src/Grafoscopio/GrafoscopioNotebook.class.st

802 lines
24 KiB
Smalltalk

"
I am a Grafoscopio Notebook.
Example:
| testTree nb |
testTree := GrafoscopioNode new becomeDefaultTestTree.
nb := GrafoscopioNotebook new.
nb notebookContent: testTree.
nb openWithSpec
"
Class {
#name : #GrafoscopioNotebook,
#superclass : #ComposableModel,
#instVars : [
'tree',
'header',
'body',
'links',
'windowMainMenu',
'workingFile',
'notebook',
'debugMessage'
],
#category : #'Grafoscopio-UI'
}
{ #category : #utility }
GrafoscopioNotebook class >> SHA1For: aFile is: aSHA1String [
"I verify that a file has the same signature that the one in a given string,
returning true in that case or false otherwise"
^ (SHA1 new hashMessage: aFile asFileReference binaryReadStream contents) hex = aSHA1String
]
{ #category : #specs }
GrafoscopioNotebook class >> defaultSpec [
"comment stating purpose of message"
^ SpecLayout composed
newColumn: [:tcol|
tcol newRow: [ :wrow | wrow add: #windowMainMenu ] height: (self toolbarHeight);
newRow: [:row |
row newColumn: [ :tc |
tc add: #tree
] width: 300.
row newColumn: [ :bc |
bc newRow: [ :bcr | bcr add: #header ] height: self toolbarHeight.
bc add: #body; add: #links height: self toolbarHeight ]]]
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> addNode [
| addedNode |
addedNode := tree highlightedItem content addNodeAfterMe.
self notebookContent: notebook.
]
{ #category : #operation }
GrafoscopioNotebook >> autoSaveBodyOf: aNode [
| playground |
body body class = TextModel
ifTrue: [ body body whenTextChanged: [ :arg | aNode body: arg ] ].
body body class = GlamourPresentationModel
ifFalse: [ ^ self ].
playground := body body glmPres.
playground
onChangeOfPort: #text
act: [ :x | aNode body: x entity value content ]";
onChangeOfPort: #activePresentation
act: [ aNode output: aNode processOutput ]"
]
{ #category : #accessing }
GrafoscopioNotebook >> body [
^ body
]
{ #category : #accessing }
GrafoscopioNotebook >> body: anObject [
body := anObject
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> copyNodeToClipboard [
tree highlightedItem content copyToClipboard.
self notebookContent: notebook.
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> cutNodeToClipboard [
self copyNodeToClipboard; removeNode.
]
{ #category : #accessing }
GrafoscopioNotebook >> debugMessage [
^ debugMessage ifNil: [ self defineDebugMessageUI ]
]
{ #category : #accessing }
GrafoscopioNotebook >> debugMessage: aGrafoscopioNodeSelector [
"I define a message that can be used for debugging purposes in the current notebook."
debugMessage := aGrafoscopioNodeSelector
]
{ #category : #operation }
GrafoscopioNotebook >> debugWithSelector: aSymbol [
"I invoke a message to debug in the current node. In the future the debugging scope can be changed to
include different elements instead of the current node."
| currentNode nodeContent |
currentNode := tree highlightedItem.
currentNode ifNil: [ ^ self ].
nodeContent := currentNode content.
^ (nodeContent perform: aSymbol asSymbol) inspect
]
{ #category : #'as yet unclassified' }
GrafoscopioNotebook >> defineDebugMessageUI [
| answer |
answer := UIManager default
request: 'Define debug message to be send to a selected node in this notebook.'
initialAnswer: 'messageNoDebugSelector'.
self debugMessage: answer
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> demoteNode [
| editedNode |
editedNode := tree highlightedItem content.
editedNode demote.
self notebookContent: notebook.
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAllSubtreesAsMarkdow [
| toBeExported |
toBeExported := self notebook selectMarkdownSubtreesToExport.
toBeExported ifEmpty: [ ^ self ].
toBeExported do: [ :each | self subtreeAsMarkdownFor: each ].
self inform: toBeExported size asString , ' exported markdown subtrees.'
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAsHTML [
"I export the current tree/document to a HTML file, using pandoc external app.
I suppose pandoc is already installed and available in the system."
| htmlFile |
self markdownFile exists ifTrue: [ self markdownFile delete ].
self exportAsMarkdown.
htmlFile := self markdownFile parent fullName,'/', self markdownFile basenameWithoutExtension, '.html'.
htmlFile asFileReference exists ifTrue: [ htmlFile asFileReference delete ].
OSProcess command: 'pandoc --standalone ', self markdownFile fullName, ' -o ', htmlFile.
self inform: ('File exported as: ', String cr, htmlFile).
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAsLaTeX [
"I export the current tree/document to a LaTeX file, using pandoc external app.
I suppose pandoc is already installed and available in the system."
| texFile |
self markdownFile exists ifTrue: [ self markdownFile delete ].
self exportAsMarkdown.
texFile := self markdownFile parent fullName,'/', self markdownFile basenameWithoutExtension, '.tex'.
texFile asFileReference exists ifTrue: [ texFile asFileReference delete ].
OSProcess command: 'pandoc --standalone ', self markdownFile fullName, ' -o ', texFile.
self inform: ('File exported as: ', String cr, texFile).
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAsMarkdown [
"I export the current working tree/document to a markdown file."
workingFile
ifNil: [ self inform: 'File NOT exported. Please save the notebook on hard drive first' ]
ifNotNil: [ self exportNode: (self notebook) asMarkdownIn: (self markdownFile) ]
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAsPDF [
"I export the current tree/document to a PDF file, using pandoc and LaTeX external apps.
The latex engine used is xelatex, to minimize errors and warnings related with UTF8 support.
I suppose all them are already installed and defined in the system."
| pdfFile pandocCommand |
self markdownFile exists ifFalse: [ self exportAsMarkdown ].
pdfFile := self markdownFile parent fullName,'/', self markdownFile basenameWithoutExtension, '.pdf'.
pdfFile asFileReference exists ifTrue: [ pdfFile asFileReference delete ].
pandocCommand := 'pandoc ',
self notebook pandocOptions, ' ',
self markdownFile fullName, ' -o ', pdfFile.
Transcript show: pandocCommand.
ExternalUnixOSProcess command: pandocCommand.
self inform: ('File exported as: ', String cr, pdfFile)
]
{ #category : #persistence }
GrafoscopioNotebook >> exportAsSton: aNotebook on: aFileStream [
aNotebook flatten.
(STON writer on: aFileStream)
newLine: String crlf;
prettyPrint: true;
keepNewLines: true;
nextPut: aNotebook children
]
{ #category : #persistence }
GrafoscopioNotebook >> exportNode: aGrafoscopioNode asMarkdownIn: aFile [
"I export the current tree/document to a markdown file"
aFile exists ifTrue: [ aFile delete ].
aFile
ensureCreateFile;
writeStreamDo: [:stream | stream nextPutAll: aGrafoscopioNode asMarkdown].
self inform: 'Exported as: ', String cr, aFile fullName
]
{ #category : #api }
GrafoscopioNotebook >> extent [
^900@500
]
{ #category : #accessing }
GrafoscopioNotebook >> header [
^ header
]
{ #category : #accessing }
GrafoscopioNotebook >> header: anObject [
header := anObject
]
{ #category : #initialization }
GrafoscopioNotebook >> initializePresenter [
tree whenHighlightedItemChanged: [ :item |
tree highlightedItem ifNotNil: [self updateBodyFor: item]].
tree whenTreeUpdated: [ :item | item ifNotNil: [self updateBodyFor: item]].
header whenTextChanged: [ :arg |
(tree highlightedItem content header) = arg
ifFalse: [
(tree highlightedItem) content header: arg.
tree roots: tree roots]].
links whenTextChanged: [ :arg |
((tree highlightedItem content links) includes: arg)
ifFalse: [
(tree highlightedItem) content links add: arg.
self updateForSpecialLinks]]
]
{ #category : #initialization }
GrafoscopioNotebook >> initializeWidgets [
windowMainMenu := self topBar.
header := self newTextInput.
header autoAccept: true.
body := self newText.
body disable.
body text: '<- Select a node'.
links := self newTextInput.
tree := TreeModel new.
tree
childrenBlock: [:node | node children];
displayBlock: [:node | node title ].
self focusOrder
add: tree;
add: header;
add: body;
add: links.
self askOkToClose: true.
]
{ #category : #accessing }
GrafoscopioNotebook >> links [
^ links
]
{ #category : #accessing }
GrafoscopioNotebook >> links: anObject [
links := anObject
]
{ #category : #persistence }
GrafoscopioNotebook >> markdownFile [
"I define the location of the markdown file where the notebook will be exported"
| markdownFile |
markdownFile := (((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.markdown') asFileReference.
^ markdownFile
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> moveNodeAfter [
| editedNode |
editedNode := tree selectedItem content.
editedNode moveAfter.
self notebookContent: notebook
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> moveNodeBefore [
| editedNode |
editedNode := tree highlightedItem content.
editedNode moveBefore.
self notebookContent: notebook
]
{ #category : #utilities }
GrafoscopioNotebook >> navigateRelativePathFor: aFileString [
"Given a relative path according to location of the notebook's workingFile,
I navigate to that file if exist and create it, including subdirectories if it does not exist.
If the relative path is located in a subdirectory that shares the route with the notebooks working
file, it must start with the folders name,
without using './' to point the same shared root "
| finalLocation pathSegments |
aFileString ifEmpty: [ ^ self ].
aFileString asUrl host ifNotNil: [ ^self ].
finalLocation := workingFile parent.
pathSegments := aFileString splitOn: '/'.
pathSegments allButLastDo: [ :segment |
(segment = '..')
ifTrue: [ finalLocation := finalLocation parent ]
ifFalse: [
finalLocation := finalLocation / segment.
finalLocation exists ifFalse: [ finalLocation ensureCreateDirectory ]]].
finalLocation := finalLocation / (pathSegments last).
finalLocation exists ifFalse: [ finalLocation ensureCreateFile ].
^ finalLocation
]
{ #category : #accessing }
GrafoscopioNotebook >> notebook [
^ notebook
]
{ #category : #accessing }
GrafoscopioNotebook >> notebook: anObject [
notebook := anObject
]
{ #category : #api }
GrafoscopioNotebook >> notebookContent: aTree [
| nodeBlock |
nodeBlock:= [:gfcNode | |node|
node := TreeNodeModel new.
node
hasChildren: [ gfcNode children isNotEmpty ];
children: [ gfcNode children collect: [:subNode | nodeBlock value: subNode ]];
content: gfcNode].
tree roots: (aTree children collect:[ :gfcNode | nodeBlock value: gfcNode])
]
{ #category : #initialization }
GrafoscopioNotebook >> notebookSubMenu [
^ MenuModel new
addGroup: [ :group |
group addItem: [ :item |
item
name: 'Save';
icon: (Smalltalk ui icons iconNamed: #smallSave);
shortcut: $s command;
action: [ self saveWorkingNotebook ] ].
group addItem: [ :item |
item
name: 'Save as...';
icon: (Smalltalk ui icons iconNamed: #smallSaveAs);
action: [ self saveToFileUI ] ].
group addItem: [ :item |
item
name: 'Export as markdown';
icon: (Smalltalk ui icons iconNamed: #smallSaveAs);
action: [ self exportAsMarkdown ] ].
group addItem: [ :item |
item
name: 'Export as html';
icon: (Smalltalk ui icons iconNamed: #smallWindow);
action: [ self exportAsHTML ]].
group addItem: [ :item |
item
name: 'Export as LaTeX';
icon: (Smalltalk ui icons iconNamed: #smallPrint);
action: [ self exportAsLaTeX ]].
group addItem: [ :item |
item
name: 'Export as pdf';
icon: (Smalltalk ui icons iconNamed: #smallPrint);
action: [ self exportAsPDF ] ].
group addItem: [ :item |
item
name: 'See html';
icon: (Smalltalk ui icons iconNamed: #smallInspectIt);
action: [ self inform: 'To be implemented...']].
group addItem: [ :item |
item
name: 'See pdf';
icon: (Smalltalk ui icons iconNamed: #smallInspectIt);
action: [ self inform: 'To be implemented...' ]].
group addItem: [ :item |
item
name: 'Define debug message...';
icon: Smalltalk ui icons glamorousBug;
action: [ self defineDebugMessageUI ]]]
]
{ #category : #private }
GrafoscopioNotebook >> okToChange [
^ true
]
{ #category : #persistence }
GrafoscopioNotebook >> openDefault [
"I open a new default notebook"
| nb |
nb := self class new.
nb
notebook: (GrafoscopioNode new becomeDefaultTree);
title: ' New | Grafoscopio notebook';
notebookContent: nb notebook.
^ nb openWithSpec.
]
{ #category : #persistence }
GrafoscopioNotebook >> openFromFile: aFileName [
"I open a notebook from a file named aFileName containing a grafoscopio tree"
self workingFile: aFileName.
self notebook: ((STON fromString: self workingFile contents) at: 1) parent.
self title: self workingFile basenameWithIndicator, ' | Grafoscopio notebook'.
self notebookContent: self notebook.
^ self openWithSpec.
]
{ #category : #persistence }
GrafoscopioNotebook >> openFromFileSelector [
| fileStream nb |
fileStream := UIManager default
fileOpen: 'Choose a file'
extensions: #('ston').
fileStream ifNil: [
self inform: 'No file selected'.
^ self ].
self workingFile: fileStream name asFileReference.
nb := self class new.
nb openFromFile: self workingFile.
GrafoscopioDockingBar updateRecentNotebooksWith: workingFile
]
{ #category : #persistence }
GrafoscopioNotebook >> openFromUrl: anUrl [
"Opens a tree from a file named aFileName"
| fileName |
fileName := (anUrl splitOn: '/') last.
GrafoscopioDockingBar
downloadingFrom: anUrl
withMessage: 'Downloading document...'
into: FileLocator temp.
self class new openFromFile: (FileLocator temp / fileName)
]
{ #category : #persistence }
GrafoscopioNotebook >> openFromUrlUI [
"This method generates the UI for the openFromUrl: method, it asks for a URL from the user"
| fileUrl |
"GrafoscopioBrowser configureSettings."
fileUrl := UIManager default
textEntry: 'Enter the URL'
title: 'Open notebook from URL'.
fileUrl isNil ifTrue: [ ^nil ].
self class new openFromUrl: fileUrl
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> pasteNodeFromClipboard [
tree highlightedItem content pasteFromClipboard.
self notebookContent: notebook.
]
{ #category : #initialization }
GrafoscopioNotebook >> projectSubMenu [
^ MenuModel new
addGroup: [ :group |
group addItem: [ :item |
item
name: 'Activate remote repository...';
icon: Smalltalk ui icons smallPushpinIcon;
action: [ self inform: 'To be implemented ...' ] ].
group addItem: [ :item |
item
name: 'Activate local repository...';
icon: Smalltalk ui icons homeIcon;
action: [ self inform: 'To be implemented ...' ] ].
group addItem: [ :item |
item
name: 'Add file...';
icon: Smalltalk ui icons newerPackagesAvailableIcon;
action: [ self inform: 'To be implemented ...' ] ].
group addItem: [ :item |
item
name: 'Delete file...';
icon: Smalltalk ui icons packageDeleteIcon;
action: [ self inform: 'To be implemented ...' ] ].
group addItem: [ :item |
item
name: 'Commit to repository';
icon: Smalltalk ui icons smallScreenshotIcon;
action: [ self inform: 'To be implemented ...' ] ].
group addItem: [ :item |
item
name: 'Credentials';
icon: Smalltalk ui icons userIcon;
action: [ self inform: 'To be implemented ...' ] ] ]
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> promoteNode [
| editedNote |
editedNote := tree selectedItem content.
editedNote promote.
self notebookContent: notebook
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> removeNode [
| contentToDelete parentContent newSelectedContent children |
contentToDelete := tree selectedItem content.
parentContent := contentToDelete parent.
children := parentContent children.
children size > 1
ifTrue: [
children last = contentToDelete
ifTrue: [ newSelectedContent := children at: (children size - 1) ]
]
ifFalse: [ newSelectedContent := parentContent ].
contentToDelete parent removeNode: contentToDelete.
self notebookContent: notebook
]
{ #category : #persistence }
GrafoscopioNotebook >> saveToFile: aFileReference [
"I save the current tree/document to a file"
aFileReference ifNil: [ self inform: 'No file selected for saving. Save NOT done'. ^ self ].
workingFile := aFileReference.
self workingFile exists ifTrue: [self workingFile delete].
self workingFile ensureCreateFile.
[ self exportAsSton: self notebook on: (self workingFile writeStream)]
ensure: [ (self workingFile writeStream) ifNotNil: #close ].
self title: self workingFile basenameWithIndicator, ' | Grafoscopio notebook'.
self inform: ('File saved at: ', String cr, self workingFile fullName).
GrafoscopioDockingBar updateRecentNotebooksWith: aFileReference.
]
{ #category : #persistence }
GrafoscopioNotebook >> saveToFileUI [
| file |
file := UIManager default
fileSave: 'Export notebook to file as...'
extensions: #('ston')
path: (workingFile ifNotNil: [ workingFile parent ] ifNil: [ FileLocator documents ] ).
file
ifNil: [ self inform: 'Export cancelled'. ^ self ]
ifNotNil:[self saveToFile: file].
]
{ #category : #persistence }
GrafoscopioNotebook >> saveWorkingNotebook [
"Saves the current tree to the user predefined file location used when he/she opened it."
self workingFile
ifNil: [ self saveToFileUI ]
ifNotNil: [ self saveToFile: workingFile ].
GrafoscopioDockingBar updateRecentNotebooksWith: workingFile
]
{ #category : #persistence }
GrafoscopioNotebook >> subtreeAsMarkdown [
| currentNode |
currentNode := tree highlightedItem content.
self inform: ('Exported as: ', String cr, (self subtreeAsMarkdownFor: currentNode) fullName )
]
{ #category : #persistence }
GrafoscopioNotebook >> subtreeAsMarkdownFor: aNode [
| exportedFile |
aNode links ifEmpty: [ ^ self ].
exportedFile:= self navigateRelativePathFor: aNode links last.
exportedFile class = GrafoscopioNotebook ifTrue: [ ^ self ].
self exportNode: aNode asMarkdownIn: exportedFile.
^ exportedFile
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> toggleCodeNode [
| currentNode |
currentNode := tree highlightedItem.
(currentNode content tags = 'código')
ifTrue: [ currentNode content tagAs: '' ]
ifFalse: [ currentNode content tagAs: 'código' ].
self updateBodyFor: currentNode.
]
{ #category : #initialization }
GrafoscopioNotebook >> topBar [
^MenuModel new
addGroup: [ :group |
group addItem: [ :item |
item
name: 'Notebook';
icon: Smalltalk ui icons smallObjects;
subMenu: self notebookSubMenu ].
group addItem: [ :item |
item
name: 'Project';
icon: Smalltalk ui icons catalog;
subMenu: self projectSubMenu ] ];
addGroup: [ :group |
group addItem: [ :item |
item
name: nil;
description: 'Save notebook';
icon: Smalltalk ui icons glamorousSave;
action: [ self saveWorkingNotebook ] ].
group addItem: [ :item |
item
name: nil;
description: 'Export all markdown subtrees';
icon: Smalltalk ui icons glamorousMore;
action: [ self exportAllSubtreesAsMarkdow ] ].
group addItem: [ :item |
item
name: nil;
description: 'Cut';
icon: Smalltalk ui icons smallCut;
action: [ self cutNodeToClipboard ] ].
group addItem: [ :item |
item
name: nil;
description: 'Copy';
icon: Smalltalk ui icons smallCopy;
action: [ self copyNodeToClipboard ] ].
group addItem: [ :item |
item
name: nil;
description: 'Paste';
icon: Smalltalk ui icons smallPaste;
action: [ self pasteNodeFromClipboard ] ]];
addGroup: [ :group |
group addItem: [ :item |
item
name: nil;
description: 'Add node';
icon: MendaIcons new plusIcon;
action: [ self addNode ] ].
group addItem: [ :item |
item
name: nil;
description: 'Delete node';
icon: MendaIcons new minusIcon;
action: [ self removeNode ] ].
group addItem: [ :item |
item
name: nil;
description: 'Move node up';
icon: MendaIcons new arrowUpIcon;
action: [ self moveNodeBefore ] ].
group addItem: [ :item |
item
name: nil;
description: 'Move node down';
icon: MendaIcons new arrowDownIcon;
action: [ self moveNodeAfter ] ].
group addItem: [ :item |
item
name: nil;
description: 'Move node left';
icon: MendaIcons new arrowLeftIcon;
action: [ self promoteNode ] ].
group addItem: [ :item |
item
name: nil;
description: 'Move node right';
icon: MendaIcons new arrowRightIcon;
action: [ self demoteNode ] ]];
addGroup: [ :group |
group addItem: [ :item |
item
name: nil;
description: 'Togle: code <--> text';
icon: MendaIcons new smalltalkCodeIcon;
action: [ self toggleCodeNode ] ].
group addItem: [ :item |
item
name: nil;
description: 'Visit link';
icon: Smalltalk ui icons glamorousRight;
action: [ self visitNodeLink ] ].
group addItem: [ :item |
item
name: nil;
description: 'Reload link';
icon: Smalltalk ui icons glamorousRefresh;
action: [ self updateForSpecialLinks ] ].
group addItem: [ :item |
item
name: nil;
description: 'Tag as...';
icon: MendaIcons new tagAddIcon;
action: [ self inform: 'To be implemented...' ] ].
group addItem: [ :item |
item
name: nil;
description: 'Untag ....';
icon: MendaIcons new tagMinusIcon;
action: [ self inform: 'To be implemented...' ] ].
group addItem: [ :item |
item
name: nil;
description: 'Edit tags...';
icon: FontAwesomeIcons new tagsIcon;
action: [ self inform: 'To be implemented...' ] ]];
addGroup: [ :debug |
debug addItem: [ :item |
item
name: nil;
description: 'Debug';
icon: Smalltalk ui icons glamorousBug;
action: [ self debugWithSelector: self debugMessage ] ]]
]
{ #category : #accessing }
GrafoscopioNotebook >> tree [
^ tree
]
{ #category : #accessing }
GrafoscopioNotebook >> tree: anObject [
tree := anObject
]
{ #category : #operation }
GrafoscopioNotebook >> updateBodyFor: aNodeContainer [
| aNode |
self needRebuild: false.
tree needRebuild: false.
body needRebuild: true.
aNode := aNodeContainer content.
header text: aNode header.
body := self instantiate: aNode specModelClass new.
body content: aNode body.
links text: aNode lastLink.
self autoSaveBodyOf: aNode.
self buildWithSpecLayout: self class defaultSpec
]
{ #category : #operation }
GrafoscopioNotebook >> updateForSpecialLinks [
"I see if a node header is an url located at 'http://ws.stfx.eu', wich means that is a shared
workspace, and convert the node body to an interactive playground"
| currentNode nodeContent |
currentNode := tree highlightedItem.
currentNode ifNil: [ ^ self ].
nodeContent := currentNode content.
nodeContent links last isAsciiString ifFalse: [ ^ self ].
nodeContent links last asUrl host = 'ws.stfx.eu' ifFalse: [ ^ self ].
nodeContent
body: (ZnClient new get: nodeContent links last);
tagAs: 'código'.
self updateBodyFor: currentNode
]
{ #category : #'editing nodes' }
GrafoscopioNotebook >> visitNodeLink [
tree highlightedItem content visitLastLink.
]
{ #category : #accessing }
GrafoscopioNotebook >> windowMainMenu [
^ windowMainMenu
]
{ #category : #accessing }
GrafoscopioNotebook >> windowMainMenu: anObject [
windowMainMenu := anObject
]
{ #category : #accessing }
GrafoscopioNotebook >> workingFile [
^ workingFile
]
{ #category : #accessing }
GrafoscopioNotebook >> workingFile: aFile [
workingFile := aFile.
]