Fixes #14173, other modular computer file manager improvements

This commit is contained in:
Heroman3003
2023-02-05 13:56:38 +10:00
committed by CHOMPStation2
parent fb1b9498ad
commit 71da50bf43
4 changed files with 86 additions and 46 deletions

View File

@@ -291,4 +291,10 @@
if(autorun.stored_data == program) if(autorun.stored_data == program)
autorun.stored_data = null autorun.stored_data = null
else else
autorun.stored_data = program autorun.stored_data = program
/obj/item/modular_computer/proc/find_file_by_uid(var/uid)
if(hard_drive)
. = hard_drive.find_file_by_uid(uid)
if(portable_drive && !.)
. = portable_drive.find_file_by_uid(uid)

View File

@@ -25,7 +25,7 @@
switch(action) switch(action)
if("PRG_openfile") if("PRG_openfile")
open_file = params["name"] open_file = params["uid"]
return TRUE return TRUE
if("PRG_newtextfile") if("PRG_newtextfile")
if(!HDD) if(!HDD)
@@ -33,19 +33,20 @@
var/newname = sanitize(tgui_input_text(usr, "Enter file name or leave blank to cancel:", "File rename")) var/newname = sanitize(tgui_input_text(usr, "Enter file name or leave blank to cancel:", "File rename"))
if(!newname) if(!newname)
return return
var/datum/computer_file/data/F = new/datum/computer_file/data() if(HDD.find_file_by_name(newname))
error = "I/O error: File already exists."
return
var/datum/computer_file/data/F = new/datum/computer_file/data/text()
F.filename = newname F.filename = newname
F.filetype = "TXT"
HDD.store_file(F) HDD.store_file(F)
return TRUE return TRUE
if("PRG_closefile") if("PRG_closefile")
open_file = null open_file = null
error = null
return TRUE return TRUE
if("PRG_clone") if("PRG_clone")
if(!HDD) if(!HDD)
return return
var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) var/datum/computer_file/F = HDD.find_file_by_uid(params["uid"])
if(!F || !istype(F)) if(!F || !istype(F))
return return
var/datum/computer_file/C = F.clone(1) var/datum/computer_file/C = F.clone(1)
@@ -56,7 +57,7 @@
return return
if(!open_file) if(!open_file)
return return
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) var/datum/computer_file/data/F = computer.find_file_by_uid(open_file)
if(!F || !istype(F)) if(!F || !istype(F))
return return
if(F.do_not_edit && (tgui_alert(usr, "WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", list("No", "Yes")) == "No")) if(F.do_not_edit && (tgui_alert(usr, "WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", list("No", "Yes")) == "No"))
@@ -65,82 +66,86 @@
var/oldtext = html_decode(F.stored_data) var/oldtext = html_decode(F.stored_data)
oldtext = replacetext(oldtext, "\[br\]", "\n") oldtext = replacetext(oldtext, "\[br\]", "\n")
var/newtext = sanitize(replacetext(tgui_input_text(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext, MAX_TEXTFILE_LENGTH, TRUE, prevent_enter = TRUE), "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) var/newtext = sanitize(replacetext(tgui_input_text(usr, "Editing file [F.filename].[F.filetype]. You may use most tags used in paper formatting:", "Text Editor", oldtext, MAX_TEXTFILE_LENGTH, TRUE, prevent_enter = TRUE), "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
if(!newtext) if(!newtext)
return return
if(F) if(F)
var/datum/computer_file/data/backup = F.clone() var/datum/computer_file/data/backup = F.clone()
HDD.remove_file(F) F.holder.remove_file(F)
F.stored_data = newtext F.stored_data = newtext
F.calculate_size() F.calculate_size()
// We can't store the updated file, it's probably too large. Print an error and restore backed up version. // We can't store the updated file, it's probably too large. Print an error and restore backed up version.
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
// They will be able to copy-paste the text from error screen and store it in notepad or something. // They will be able to copy-paste the text from error screen and store it in notepad or something.
if(!HDD.store_file(F)) if(!F.holder.store_file(F))
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>" error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
HDD.store_file(backup) F.holder.store_file(backup)
return TRUE return TRUE
if("PRG_printfile") if("PRG_printfile")
if(!HDD) if(!HDD)
return return
if(!open_file) if(!open_file)
return return
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) var/datum/computer_file/data/F = computer.find_file_by_uid(open_file)
if(!F || !istype(F)) if(!F || !istype(F))
return return
if(!computer.nano_printer) if(!computer.nano_printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation." error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return return TRUE
if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
error = "Hardware error: Printer was unable to print the file. It may be out of paper." error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return return TRUE
return TRUE return TRUE
if("PRG_deletefile") if("PRG_deletefile")
if(!HDD) if(!HDD)
return return
var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) var/datum/computer_file/file = computer.find_file_by_uid(params["uid"])
if(!file || file.undeletable) if(!file || file.undeletable)
return return
HDD.remove_file(file) file.holder.remove_file(file)
return TRUE
if("PRG_usbdeletefile")
if(!RHDD)
return
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
if(!file || file.undeletable)
return
RHDD.remove_file(file)
return TRUE return TRUE
if("PRG_rename") if("PRG_rename")
if(!HDD) if(!HDD)
return return
var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) var/datum/computer_file/file = computer.find_file_by_uid(params["uid"])
if(!file) if(!file)
return return
var/newname = params["new_name"] var/newname = params["new_name"]
if(!newname) if(!newname)
return return
if(file.holder.find_file_by_name(newname))
error = "I/O error: File already exists."
return TRUE
file.filename = newname file.filename = newname
return TRUE return TRUE
if("PRG_copytousb") if("PRG_copytousb")
if(!HDD || !RHDD) if(!HDD || !RHDD)
return return
var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) var/datum/computer_file/F = HDD.find_file_by_uid(params["uid"])
if(!F) if(!F)
return return
var/datum/computer_file/C = F.clone(FALSE) var/datum/computer_file/C = F.clone(FALSE)
if(!RHDD.try_store_file(C))
error = "I/O error: File already exists or insufficient space on drive."
return TRUE
RHDD.store_file(C) RHDD.store_file(C)
return TRUE return TRUE
if("PRG_copyfromusb") if("PRG_copyfromusb")
if(!HDD || !RHDD) if(!HDD || !RHDD)
return return
var/datum/computer_file/F = RHDD.find_file_by_name(params["name"]) var/datum/computer_file/F = RHDD.find_file_by_uid(params["uid"])
if(!F || !istype(F)) if(!F || !istype(F))
return return
var/datum/computer_file/C = F.clone(FALSE) var/datum/computer_file/C = F.clone(FALSE)
if(!HDD.try_store_file(C))
error = "I/O error: File already exists or insufficient space on drive."
return TRUE
HDD.store_file(C) HDD.store_file(C)
return TRUE return TRUE
if("PRG_clearerror")
error = null
return TRUE
/datum/computer_file/program/filemanager/tgui_data(mob/user) /datum/computer_file/program/filemanager/tgui_data(mob/user)
var/list/data = get_header_data() var/list/data = get_header_data()
@@ -163,10 +168,10 @@
if(open_file) if(open_file)
var/datum/computer_file/data/file var/datum/computer_file/data/file
if(!computer || !computer.hard_drive) if(!computer || (!computer.hard_drive && computer.portable_drive))
data["error"] = "I/O ERROR: Unable to access hard drive." data["error"] = "I/O ERROR: Unable to access hard drive."
else else
file = HDD.find_file_by_name(open_file) file = computer.find_file_by_uid(open_file)
if(!istype(file)) if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file." data["error"] = "I/O ERROR: Unable to open file."
else else
@@ -178,6 +183,7 @@
files += list(list( files += list(list(
"name" = F.filename, "name" = F.filename,
"type" = F.filetype, "type" = F.filetype,
"uid" = F.uid,
"size" = F.size, "size" = F.size,
"undeletable" = F.undeletable "undeletable" = F.undeletable
)) ))
@@ -189,6 +195,7 @@
usbfiles += list(list( usbfiles += list(list(
"name" = F.filename, "name" = F.filename,
"type" = F.filetype, "type" = F.filetype,
"uid" = F.uid,
"size" = F.size, "size" = F.size,
"undeletable" = F.undeletable "undeletable" = F.undeletable
)) ))

View File

@@ -161,6 +161,21 @@
return F return F
return null return null
// Tries to find the file by unique ID. Returns null on failure
/obj/item/weapon/computer_hardware/hard_drive/proc/find_file_by_uid(var/uid)
if(!check_functionality())
return null
if(!uid)
return null
if(!stored_files)
return null
for(var/datum/computer_file/F in stored_files)
if(F.uid == uid)
return F
/obj/item/weapon/computer_hardware/hard_drive/Destroy() /obj/item/weapon/computer_hardware/hard_drive/Destroy()
if(holder2 && (holder2.hard_drive == src)) if(holder2 && (holder2.hard_drive == src))
holder2.hard_drive = null holder2.hard_drive = null

View File

@@ -1,7 +1,7 @@
/* eslint react/no-danger: "off" */ /* eslint react/no-danger: "off" */
import { Fragment } from 'inferno'; import { Fragment } from 'inferno';
import { useBackend } from '../backend'; import { useBackend } from '../backend';
import { Button, Section, Table } from '../components'; import { Button, Section, Table, Flex } from '../components';
import { NtosWindow } from '../layouts'; import { NtosWindow } from '../layouts';
export const NtosFileManager = (props, context) => { export const NtosFileManager = (props, context) => {
@@ -10,7 +10,7 @@ export const NtosFileManager = (props, context) => {
return ( return (
<NtosWindow resizable theme={PC_device_theme}> <NtosWindow resizable theme={PC_device_theme}>
<NtosWindow.Content scrollable> <NtosWindow.Content scrollable>
{((filename || error) && ( {(filename && (
<Section <Section
title={'Viewing File ' + filename} title={'Viewing File ' + filename}
buttons={ buttons={
@@ -20,7 +20,6 @@ export const NtosFileManager = (props, context) => {
<Button icon="times" content="Close" onClick={() => act('PRG_closefile')} /> <Button icon="times" content="Close" onClick={() => act('PRG_closefile')} />
</Fragment> </Fragment>
}> }>
{error || null}
{/* This dangerouslySetInnerHTML is only ever passed data that has passed through pencode2html {/* This dangerouslySetInnerHTML is only ever passed data that has passed through pencode2html
* It should be safe enough to support pencode in this way. * It should be safe enough to support pencode in this way.
*/} */}
@@ -32,16 +31,16 @@ export const NtosFileManager = (props, context) => {
<FileTable <FileTable
files={files} files={files}
usbconnected={usbconnected} usbconnected={usbconnected}
onUpload={(file) => act('PRG_copytousb', { name: file })} onUpload={(file) => act('PRG_copytousb', { uid: file })}
onDelete={(file) => act('PRG_deletefile', { name: file })} onDelete={(file) => act('PRG_deletefile', { uid: file })}
onOpen={(file) => act('PRG_openfile', { name: file })} onOpen={(file) => act('PRG_openfile', { uid: file })}
onRename={(file, newName) => onRename={(file, newName) =>
act('PRG_rename', { act('PRG_rename', {
name: file, uid: file,
new_name: newName, new_name: newName,
}) })
} }
onDuplicate={(file) => act('PRG_clone', { file: file })} onDuplicate={(file) => act('PRG_clone', { uid: file })}
/> />
</Section> </Section>
{(usbconnected && ( {(usbconnected && (
@@ -50,15 +49,16 @@ export const NtosFileManager = (props, context) => {
usbmode usbmode
files={usbfiles} files={usbfiles}
usbconnected={usbconnected} usbconnected={usbconnected}
onUpload={(file) => act('PRG_copyfromusb', { name: file })} onUpload={(file) => act('PRG_copyfromusb', { uid: file })}
onDelete={(file) => act('PRG_deletefile', { name: file })} onDelete={(file) => act('PRG_deletefile', { uid: file })}
onOpen={(file) => act('PRG_openfile', { uid: file })}
onRename={(file, newName) => onRename={(file, newName) =>
act('PRG_rename', { act('PRG_rename', {
name: file, uid: file,
new_name: newName, new_name: newName,
}) })
} }
onDuplicate={(file) => act('PRG_clone', { file: file })} onDuplicate={(file) => act('PRG_clone', { uid: file })}
/> />
</Section> </Section>
)) || )) ||
@@ -70,6 +70,18 @@ export const NtosFileManager = (props, context) => {
</Section> </Section>
</Fragment> </Fragment>
)} )}
{error && (
<Flex wrap="wrap" position="fixed" bottom="5px">
<Flex.Item>
<Section>
<Button bottom="0" left="0" icon="ban" onClick={() => act('PRG_clearerror')} />
</Section>
</Flex.Item>
<Section>
<Flex.Item grow>{error}</Flex.Item>
</Section>
</Flex>
)}
</NtosWindow.Content> </NtosWindow.Content>
</NtosWindow> </NtosWindow>
); );
@@ -94,9 +106,9 @@ const FileTable = (props) => {
content={file.name} content={file.name}
currentValue={file.name} currentValue={file.name}
tooltip="Rename" tooltip="Rename"
onCommit={(e, value) => onRename(file.name, value)} onCommit={(e, value) => onRename(file.uid, value)}
/> />
<Button content="Open" onClick={() => onOpen(file.name)} /> <Button content="Open" onClick={() => onOpen(file.uid)} />
</Fragment> </Fragment>
) : ( ) : (
file.name file.name
@@ -112,13 +124,13 @@ const FileTable = (props) => {
confirmIcon="times" confirmIcon="times"
confirmContent="" confirmContent=""
tooltip="Delete" tooltip="Delete"
onClick={() => onDelete(file.name)} onClick={() => onDelete(file.uid)}
/> />
{!!usbconnected && {!!usbconnected &&
(usbmode ? ( (usbmode ? (
<Button icon="download" tooltip="Download" onClick={() => onUpload(file.name)} /> <Button icon="download" tooltip="Download" onClick={() => onUpload(file.uid)} />
) : ( ) : (
<Button icon="upload" tooltip="Upload" onClick={() => onUpload(file.name)} /> <Button icon="upload" tooltip="Upload" onClick={() => onUpload(file.uid)} />
))} ))}
</Fragment> </Fragment>
)} )}