diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index 8639aadb63..827b7204f8 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -291,4 +291,10 @@ if(autorun.stored_data == program) autorun.stored_data = null else - autorun.stored_data = program \ No newline at end of file + 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) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm index 30719cf0be..54e66497ea 100644 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm @@ -25,7 +25,7 @@ switch(action) if("PRG_openfile") - open_file = params["name"] + open_file = params["uid"] return TRUE if("PRG_newtextfile") if(!HDD) @@ -33,19 +33,20 @@ var/newname = sanitize(tgui_input_text(usr, "Enter file name or leave blank to cancel:", "File rename")) if(!newname) 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.filetype = "TXT" HDD.store_file(F) return TRUE if("PRG_closefile") open_file = null - error = null return TRUE if("PRG_clone") if(!HDD) 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)) return var/datum/computer_file/C = F.clone(1) @@ -56,7 +57,7 @@ return if(!open_file) 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)) 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")) @@ -65,82 +66,86 @@ var/oldtext = html_decode(F.stored_data) 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) return if(F) var/datum/computer_file/data/backup = F.clone() - HDD.remove_file(F) + F.holder.remove_file(F) F.stored_data = newtext F.calculate_size() // 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. // 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:

[html_decode(F.stored_data)]

" - HDD.store_file(backup) + F.holder.store_file(backup) return TRUE if("PRG_printfile") if(!HDD) return if(!open_file) 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)) return if(!computer.nano_printer) 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))) error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return + return TRUE return TRUE if("PRG_deletefile") if(!HDD) 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) return - HDD.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) + file.holder.remove_file(file) return TRUE if("PRG_rename") if(!HDD) 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) return var/newname = params["new_name"] if(!newname) return + if(file.holder.find_file_by_name(newname)) + error = "I/O error: File already exists." + return TRUE file.filename = newname return TRUE if("PRG_copytousb") if(!HDD || !RHDD) 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) return 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) return TRUE if("PRG_copyfromusb") if(!HDD || !RHDD) 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)) return 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) return TRUE + if("PRG_clearerror") + error = null + return TRUE /datum/computer_file/program/filemanager/tgui_data(mob/user) var/list/data = get_header_data() @@ -163,10 +168,10 @@ if(open_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." else - file = HDD.find_file_by_name(open_file) + file = computer.find_file_by_uid(open_file) if(!istype(file)) data["error"] = "I/O ERROR: Unable to open file." else @@ -178,6 +183,7 @@ files += list(list( "name" = F.filename, "type" = F.filetype, + "uid" = F.uid, "size" = F.size, "undeletable" = F.undeletable )) @@ -189,6 +195,7 @@ usbfiles += list(list( "name" = F.filename, "type" = F.filetype, + "uid" = F.uid, "size" = F.size, "undeletable" = F.undeletable )) diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm index e365ff16e6..09ccde9e49 100644 --- a/code/modules/modular_computers/hardware/hard_drive.dm +++ b/code/modules/modular_computers/hardware/hard_drive.dm @@ -161,6 +161,21 @@ return F 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() if(holder2 && (holder2.hard_drive == src)) holder2.hard_drive = null diff --git a/tgui/packages/tgui/interfaces/NtosFileManager.js b/tgui/packages/tgui/interfaces/NtosFileManager.js index da0d5894d6..072a4fef1e 100644 --- a/tgui/packages/tgui/interfaces/NtosFileManager.js +++ b/tgui/packages/tgui/interfaces/NtosFileManager.js @@ -1,7 +1,7 @@ /* eslint react/no-danger: "off" */ import { Fragment } from 'inferno'; import { useBackend } from '../backend'; -import { Button, Section, Table } from '../components'; +import { Button, Section, Table, Flex } from '../components'; import { NtosWindow } from '../layouts'; export const NtosFileManager = (props, context) => { @@ -10,7 +10,7 @@ export const NtosFileManager = (props, context) => { return ( - {((filename || error) && ( + {(filename && (
{
{(usbconnected && ( @@ -50,15 +49,16 @@ export const NtosFileManager = (props, context) => { usbmode files={usbfiles} usbconnected={usbconnected} - onUpload={(file) => act('PRG_copyfromusb', { name: file })} - onDelete={(file) => act('PRG_deletefile', { name: file })} + onUpload={(file) => act('PRG_copyfromusb', { uid: file })} + onDelete={(file) => act('PRG_deletefile', { uid: file })} + onOpen={(file) => act('PRG_openfile', { uid: file })} onRename={(file, newName) => act('PRG_rename', { - name: file, + uid: file, new_name: newName, }) } - onDuplicate={(file) => act('PRG_clone', { file: file })} + onDuplicate={(file) => act('PRG_clone', { uid: file })} /> )) || @@ -70,6 +70,25 @@ export const NtosFileManager = (props, context) => { )} + {error && ( + + +
+
+
+
+ + {error} + +
+
+ )}
); @@ -94,9 +113,9 @@ const FileTable = (props) => { content={file.name} currentValue={file.name} tooltip="Rename" - onCommit={(e, value) => onRename(file.name, value)} + onCommit={(e, value) => onRename(file.uid, value)} /> -