mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 18:16:31 +03:00
Added keyboard shortcut operations in the file system tree view, to complete SpartanJ/ecode#71.
This commit is contained in:
@@ -39,9 +39,9 @@ class EE_API FileSystem {
|
||||
*/
|
||||
static bool fileGet( const std::string& path, std::string& data );
|
||||
|
||||
/** Copy a file to location.
|
||||
* @param src Source File Path
|
||||
* @param dst Destination File Path
|
||||
/** Copy a file or a directory (recursively) to location.
|
||||
* @param src Source file / directory Path
|
||||
* @param dst Destination file path
|
||||
* @return If success.
|
||||
*/
|
||||
static bool fileCopy( const std::string& src, const std::string& dst );
|
||||
@@ -79,6 +79,12 @@ class EE_API FileSystem {
|
||||
/** Deletes a file from the file system. */
|
||||
static bool fileRemove( const std::string& filepath );
|
||||
|
||||
/** Moves a file or folder to the destination path
|
||||
* @param fromPath The path of the file or folder to move
|
||||
* @param toPath The folder / directory destination path
|
||||
*/
|
||||
static bool fileMove( const std::string& fromPath, const std::string& toPath );
|
||||
|
||||
/** Hides the file in the file system */
|
||||
static bool fileHide( const std::string& filepath );
|
||||
|
||||
@@ -172,6 +178,7 @@ class EE_API FileSystem {
|
||||
|
||||
/** Opens a file path with a path and mode encoded in UTF-8 */
|
||||
static FILE* fopenUtf8( const std::string& path, const std::string& mode );
|
||||
|
||||
};
|
||||
|
||||
}} // namespace EE::System
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <eepp/system/iostreamfile.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
#include <sys/stat.h>
|
||||
#include <filesystem>
|
||||
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
@@ -93,38 +94,32 @@ bool FileSystem::fileGet( const std::string& path, std::string& data ) {
|
||||
}
|
||||
|
||||
bool FileSystem::fileCopy( const std::string& src, const std::string& dst ) {
|
||||
if ( fileExists( src ) ) {
|
||||
Int64 chunksize = EE_1MB;
|
||||
Int64 size = fileSize( src );
|
||||
Int64 size_left = (Int32)size;
|
||||
Int64 allocate = ( size < chunksize ) ? size : chunksize;
|
||||
Int64 copysize = 0;
|
||||
try {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::filesystem::path source = String( src ).toWideString();
|
||||
std::filesystem::path destination = String( dst ).toWideString();
|
||||
#else
|
||||
std::filesystem::path source = src;
|
||||
std::filesystem::path destination = dst;
|
||||
#endif
|
||||
|
||||
TScopedBuffer<char> data( allocate );
|
||||
char* buff = data.get();
|
||||
if ( !std::filesystem::exists( source ) )
|
||||
return false;
|
||||
|
||||
IOStreamFile in( src, "rb" );
|
||||
IOStreamFile out( dst, "wb" );
|
||||
|
||||
if ( in.isOpen() && out.isOpen() && size > 0 ) {
|
||||
do {
|
||||
if ( size_left - chunksize < 0 ) {
|
||||
copysize = size_left;
|
||||
} else {
|
||||
copysize = chunksize;
|
||||
}
|
||||
|
||||
in.read( &buff[0], copysize );
|
||||
out.write( &buff[0], copysize );
|
||||
|
||||
size_left -= copysize;
|
||||
} while ( size_left > 0 );
|
||||
|
||||
return true;
|
||||
if ( std::filesystem::is_directory( source ) ) {
|
||||
std::filesystem::copy( source, destination,
|
||||
std::filesystem::copy_options::recursive |
|
||||
std::filesystem::copy_options::overwrite_existing );
|
||||
} else {
|
||||
std::filesystem::copy( source, destination,
|
||||
std::filesystem::copy_options::overwrite_existing );
|
||||
}
|
||||
return true;
|
||||
} catch ( const std::filesystem::filesystem_error& ) {
|
||||
return false;
|
||||
} catch ( const std::exception& ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string FileSystem::fileExtension( const std::string& filepath, const bool& lowerExt ) {
|
||||
@@ -710,4 +705,19 @@ FILE* FileSystem::fopenUtf8( const std::string& path, const std::string& mode )
|
||||
return fopenUtf8( path.c_str(), mode.c_str() );
|
||||
}
|
||||
|
||||
bool FileSystem::fileMove( const std::string& fpath, const std::string& newFilePath ) {
|
||||
try {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::filesystem::rename( String( fpath ).toWideString(),
|
||||
String( newFilePath ).toWideString() );
|
||||
#else
|
||||
std::filesystem::rename( fpath, newFilePath );
|
||||
#endif
|
||||
} catch ( const std::filesystem::filesystem_error& ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // namespace EE::System
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ecode.hpp"
|
||||
#include "customwidgets.hpp"
|
||||
#include "featureshealth.hpp"
|
||||
#include "keybindingshelper.hpp"
|
||||
#include "pathhelper.hpp"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ECODE_HPP
|
||||
|
||||
#include "appconfig.hpp"
|
||||
#include "customwidgets.hpp"
|
||||
#include "docsearchcontroller.hpp"
|
||||
#include "featureshealth.hpp"
|
||||
#include "filesystemlistener.hpp"
|
||||
|
||||
@@ -8,8 +8,15 @@ using namespace EE::Scene;
|
||||
|
||||
namespace ecode {
|
||||
|
||||
NotificationCenter* sInstance = nullptr;
|
||||
|
||||
NotificationCenter* NotificationCenter::instance() {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
NotificationCenter::NotificationCenter( UILayout* layout, PluginManager* pluginManager ) :
|
||||
mLayout( layout ), mPluginManager( pluginManager ) {
|
||||
sInstance = this;
|
||||
mPluginManager->subscribeMessages(
|
||||
"notificationcenter", [this]( const PluginMessage& msg ) -> PluginRequestHandle {
|
||||
if ( !msg.isBroadcast() )
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace ecode {
|
||||
|
||||
class NotificationCenter {
|
||||
public:
|
||||
static NotificationCenter* instance();
|
||||
|
||||
NotificationCenter( UILayout* layout, PluginManager* pluginManager );
|
||||
|
||||
void addNotification( const String& text, const Time& delay = Seconds( 2.5 ),
|
||||
|
||||
@@ -1306,26 +1306,11 @@ void LLMChatUI::updateTabTitle() {
|
||||
tab->setText( title );
|
||||
}
|
||||
|
||||
static bool fsRenameFile( const std::string& fpath, const std::string& newFilePath ) {
|
||||
try {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::filesystem::rename( String( fpath ).toWideString(),
|
||||
String( newFilePath ).toWideString() );
|
||||
#else
|
||||
std::filesystem::rename( fpath, newFilePath );
|
||||
#endif
|
||||
} catch ( const std::filesystem::filesystem_error& ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLMChatUI::renameChat( const std::string& newName, bool invertLockedState ) {
|
||||
auto oldPath = getNewFilePath( mUUID.toString(), mSummary, mChatLocked );
|
||||
auto newPath =
|
||||
getNewFilePath( mUUID.toString(), newName, invertLockedState ? !mChatLocked : mChatLocked );
|
||||
if ( fsRenameFile( oldPath, newPath ) ) {
|
||||
if ( FileSystem::fileMove( oldPath, newPath ) ) {
|
||||
mSummary = newName;
|
||||
if ( invertLockedState )
|
||||
mChatLocked = !mChatLocked;
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
#include "uitreeviewfs.hpp"
|
||||
#include "customwidgets.hpp"
|
||||
#include "notificationcenter.hpp"
|
||||
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/models/filesystemmodel.hpp>
|
||||
#include <eepp/ui/uimessagebox.hpp>
|
||||
#include <eepp/window/cursormanager.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace ecode {
|
||||
|
||||
static const std::map<KeyBindings::Shortcut, std::string> getDefaultKeybindings() {
|
||||
return {
|
||||
{ { KEY_C, KeyMod::getDefaultModifier() }, "copy" },
|
||||
{ { KEY_X, KeyMod::getDefaultModifier() }, "cut" },
|
||||
{ { KEY_V, KeyMod::getDefaultModifier() }, "paste" },
|
||||
};
|
||||
}
|
||||
|
||||
class UITreeViewCellFS : public UITreeViewCell {
|
||||
public:
|
||||
static UITextView* sDragTV;
|
||||
@@ -30,7 +37,9 @@ class UITreeViewCellFS : public UITreeViewCell {
|
||||
return widget->isType( static_cast<Uint32>( CustomWidgets::UI_TYPE_TREEVIEWCELLFS ) );
|
||||
}
|
||||
|
||||
UITreeViewFS* getTreeView() const { return getParent()->getParent()->asType<UITreeViewFS>(); }
|
||||
inline UITreeViewFS* getTreeView() const {
|
||||
return getParent()->getParent()->asType<UITreeViewFS>();
|
||||
}
|
||||
|
||||
const FileSystemModel* getModel() const {
|
||||
auto model = getParent()->getParent()->asType<UITreeView>()->getModel();
|
||||
@@ -95,6 +104,14 @@ class UITreeViewCellFS : public UITreeViewCell {
|
||||
getEventDispatcher()->setNodeDragging( nullptr );
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string cmd = getTreeView()->getKeyBindings().getCommandFromKeyBind(
|
||||
{ event.getKeyCode(), event.getMod() } );
|
||||
if ( !cmd.empty() ) {
|
||||
getTreeView()->execute( cmd );
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -108,7 +125,33 @@ class UITreeViewCellFS : public UITreeViewCell {
|
||||
|
||||
UITextView* UITreeViewCellFS::sDragTV = nullptr;
|
||||
|
||||
UITreeViewFS::UITreeViewFS() : UITreeView() {}
|
||||
UITreeViewFS::UITreeViewFS() : UITreeView(), mKeyBindings( getInput() ) {
|
||||
mCommands["copy"] = [this] {
|
||||
if ( getSelection().isEmpty() )
|
||||
return;
|
||||
mSrcCopy = getSelectionPath();
|
||||
mWasCut = false;
|
||||
NotificationCenter::instance()->addNotification(
|
||||
String::format( i18n( "copied_file", "Copied '%s'" ).toUtf8(),
|
||||
FileSystem::fileNameFromPath( mSrcCopy ) ) );
|
||||
};
|
||||
|
||||
mCommands["cut"] = [this] {
|
||||
if ( getSelection().isEmpty() )
|
||||
return;
|
||||
mSrcCopy = getSelectionPath();
|
||||
mWasCut = true;
|
||||
NotificationCenter::instance()->addNotification( String::format(
|
||||
i18n( "cut_file", "Cut '%s'" ).toUtf8(), FileSystem::fileNameFromPath( mSrcCopy ) ) );
|
||||
};
|
||||
|
||||
mCommands["paste"] = [this] {
|
||||
if ( mWasCut )
|
||||
moveFile( mSrcCopy, getSelectionPath() );
|
||||
};
|
||||
|
||||
mKeyBindings.addKeybinds( getDefaultKeybindings() );
|
||||
}
|
||||
|
||||
UIWidget* UITreeViewFS::createCell( UIWidget* rowWidget, const ModelIndex& index ) {
|
||||
auto* widget = UITreeViewCellFS::New();
|
||||
@@ -130,21 +173,6 @@ Uint32 UITreeViewFS::onMessage( const NodeMessage* msg ) {
|
||||
return UITreeView::onMessage( msg );
|
||||
}
|
||||
|
||||
static bool fsRenameFile( const std::string& fpath, const std::string& newFilePath ) {
|
||||
try {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
std::filesystem::rename( String( fpath ).toWideString(),
|
||||
String( newFilePath ).toWideString() );
|
||||
#else
|
||||
std::filesystem::rename( fpath, newFilePath );
|
||||
#endif
|
||||
} catch ( const std::filesystem::filesystem_error& ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UITreeViewFS::moveFile( const std::string& src, const std::string& dst ) {
|
||||
FileInfo srcInfo( src );
|
||||
if ( !srcInfo.exists() )
|
||||
@@ -179,11 +207,48 @@ void UITreeViewFS::moveFile( const std::string& src, const std::string& dst ) {
|
||||
partialSrc, partialDst ) );
|
||||
|
||||
UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::OK_CANCEL, confirmMsg );
|
||||
msgBox->setTitle( "ecode" );
|
||||
msgBox->center();
|
||||
msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } );
|
||||
msgBox->showWhenReady();
|
||||
msgBox->on( Event::OnConfirm, [srcPath = std::move( srcPath ), dstPath = std::move( dstPath )](
|
||||
auto ) { fsRenameFile( srcPath, dstPath ); } );
|
||||
auto ) { FileSystem::fileMove( srcPath, dstPath ); } );
|
||||
}
|
||||
|
||||
void UITreeViewFS::copyFile( const std::string& src, const std::string& dst ) {
|
||||
FileInfo srcInfo( src );
|
||||
if ( !srcInfo.exists() )
|
||||
return;
|
||||
FileInfo dstInfo( dst );
|
||||
if ( !dstInfo.exists() )
|
||||
return;
|
||||
if ( srcInfo.getFilepath() != srcInfo.getRealPath() )
|
||||
srcInfo = FileInfo( srcInfo.getRealPath() );
|
||||
if ( !dstInfo.isDirectory() ) {
|
||||
dstInfo = FileInfo( dstInfo.getDirectoryPath() );
|
||||
if ( dstInfo.getFilepath() != dstInfo.getRealPath() )
|
||||
dstInfo = FileInfo( dstInfo.getRealPath() );
|
||||
}
|
||||
if ( srcInfo.getDirectoryPath() == dstInfo.getFilepath() )
|
||||
return;
|
||||
|
||||
std::string srcPath( srcInfo.getFilepath() );
|
||||
std::string dstPath( dstInfo.getFilepath() );
|
||||
FileSystem::dirAddSlashAtEnd( dstPath );
|
||||
dstPath += srcInfo.getFileName();
|
||||
FileSystem::fileCopy( srcPath, dstPath );
|
||||
}
|
||||
|
||||
std::string UITreeViewFS::getSelectionPath() const {
|
||||
return static_cast<const FileSystemModel*>( getModel() )
|
||||
->node( getSelection().first() )
|
||||
.fullPath();
|
||||
}
|
||||
|
||||
void UITreeViewFS::execute( const std::string& cmd ) {
|
||||
auto cmdIt = mCommands.find( cmd );
|
||||
if ( cmdIt != mCommands.end() )
|
||||
return cmdIt->second();
|
||||
}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <eepp/ui/keyboardshortcut.hpp>
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
|
||||
using namespace EE::UI;
|
||||
@@ -16,12 +17,26 @@ class UITreeViewFS : public UITreeView {
|
||||
|
||||
Uint32 onMessage( const NodeMessage* msg ) override;
|
||||
|
||||
KeyBindings& getKeyBindings() { return mKeyBindings; }
|
||||
|
||||
void setSourceDrag( const std::string& src ) { mSrcDrag = src; }
|
||||
|
||||
void setSourceCopy( const std::string& src ) { mSrcCopy = src; }
|
||||
|
||||
void execute( const std::string& cmd );
|
||||
|
||||
protected:
|
||||
KeyBindings mKeyBindings;
|
||||
UnorderedMap<std::string, std::function<void()>> mCommands;
|
||||
std::string mSrcDrag;
|
||||
std::string mSrcCopy;
|
||||
bool mWasCut{ false };
|
||||
|
||||
std::string getSelectionPath() const;
|
||||
|
||||
void moveFile( const std::string& src, const std::string& dst );
|
||||
|
||||
void copyFile( const std::string& src, const std::string& dst );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "uiwelcomescreen.hpp"
|
||||
#include "customwidgets.hpp"
|
||||
#include "ecode.hpp"
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/window/window.hpp>
|
||||
|
||||
Reference in New Issue
Block a user