예제 #1
0
void COptions::LoadGlobalDefaultOptions(std::map<std::string, unsigned int> const& nameOptionMap)
{
	CLocalPath const defaultsDir = wxGetApp().GetDefaultsDir();
	if (defaultsDir.empty()) {
		return;
	}
	CXmlFile file(defaultsDir.GetPath() + _T("fzdefaults.xml"));
	if (!file.Load()) {
		return;
	}

	auto element = file.GetElement();
	if (!element) {
		return;
	}

	element = element.child("Settings");
	if (!element) {
		return;
	}

	for (auto setting = element.child("Setting"); setting; setting = setting.next_sibling("Setting")) {
		LoadOptionFromElement(setting, nameOptionMap, true);
	}
}
예제 #2
0
void CRemoteTreeView::OnMenuDownload(wxCommandEvent& event)
{
	CLocalPath localDir = m_pState->GetLocalDir();
	if (!localDir.IsWriteable())
	{
		wxBell();
		return;
	}

	if (!m_pState->IsRemoteIdle())
		return;

	if (!m_contextMenuItem)
		return;

	const CServerPath& path = GetPathFromItem(m_contextMenuItem);
	if (path.empty())
		return;

	const wxString& name = GetItemText(m_contextMenuItem);

	localDir.AddSegment(CQueueView::ReplaceInvalidCharacters(name));

	CRecursiveOperation* pRecursiveOperation = m_pState->GetRecursiveOperationHandler();
	pRecursiveOperation->AddDirectoryToVisit(path, _T(""), localDir);

	CServerPath currentPath;
	const wxTreeItemId selected = GetSelection();
	if (selected)
		currentPath = GetPathFromItem(selected);

	const bool addOnly = event.GetId() == XRCID("ID_ADDTOQUEUE");
	CFilterManager filter;
	pRecursiveOperation->StartRecursiveOperation(addOnly ? CRecursiveOperation::recursive_addtoqueue : CRecursiveOperation::recursive_download, path, filter.GetActiveFilters(false), true, currentPath);
}
예제 #3
0
파일: Options.cpp 프로젝트: Typz/FileZilla
COptions::COptions()
{
	m_theOptions = this;
	m_pXmlFile = 0;
	m_pLastServer = 0;

	SetDefaultValues();

	m_save_timer.SetOwner(this);

	auto const nameOptionMap = GetNameOptionMap();
	LoadGlobalDefaultOptions(nameOptionMap);

	CLocalPath const dir = InitSettingsDir();

	CInterProcessMutex mutex(MUTEX_OPTIONS);
	m_pXmlFile = new CXmlFile(dir.GetPath() + _T("filezilla.xml"));
	if (!m_pXmlFile->Load()) {
		wxString msg = m_pXmlFile->GetError() + _T("\n\n") + _("For this session the default settings will be used. Any changes to the settings will not be saved.");
		wxMessageBoxEx(msg, _("Error loading xml file"), wxICON_ERROR);
		delete m_pXmlFile;
		m_pXmlFile = 0;
	}
	else
		CreateSettingsXmlElement();

	LoadOptions(nameOptionMap);
}
bool CState::RecursiveCopy(CLocalPath source, const CLocalPath& target)
{
	if (source.empty() || target.empty())
		return false;

	if (source == target)
		return false;

	if (source.IsParentOf(target))
		return false;

	if (!source.HasParent())
		return false;

	wxString last_segment;
	if (!source.MakeParent(&last_segment))
		return false;

	std::list<wxString> dirsToVisit;
	dirsToVisit.push_back(last_segment + CLocalPath::path_separator);

	// Process any subdirs which still have to be visited
	while (!dirsToVisit.empty())
	{
		wxString dirname = dirsToVisit.front();
		dirsToVisit.pop_front();
		wxMkdir(target.GetPath() + dirname);

		CLocalFileSystem fs;
		if (!fs.BeginFindFiles(source.GetPath() + dirname, false))
			continue;

		bool is_dir, is_link;
		wxString file;
		while (fs.GetNextFile(file, is_link, is_dir, 0, 0, 0))
		{
			if (file.empty())
			{
				wxGetApp().DisplayEncodingWarning();
				continue;
			}

			if (is_dir)
			{
				if (is_link)
					continue;

				const wxString subDir = dirname + file + CLocalPath::path_separator;
				dirsToVisit.push_back(subDir);
			}
			else
				wxCopyFile(source.GetPath() + dirname + file, target.GetPath() + dirname + file);
		}
	}

	return true;
}
CServerPath CState::GetSynchronizedDirectory(CLocalPath local_path)
{
	std::list<wxString> segments;
	while (local_path.HasParent() && local_path != m_sync_browse.local_root)
	{
		wxString last;
		local_path.MakeParent(&last);
		segments.push_front(last);
	}
	if (local_path != m_sync_browse.local_root)
		return CServerPath();

	CServerPath remote_path = m_sync_browse.remote_root;
	for (std::list<wxString>::const_iterator iter = segments.begin(); iter != segments.end(); ++iter)
		remote_path.AddSegment(*iter);

	return remote_path;
}
예제 #6
0
CLocalPath COptions::GetUnadjustedSettingsDir()
{
	CLocalPath ret;

#ifdef FZ_WINDOWS
	wchar_t buffer[MAX_PATH * 2 + 1];

	if (SUCCEEDED(SHGetFolderPath(0, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, buffer))) {
		CLocalPath tmp(buffer);
		if (!tmp.empty()) {
			tmp.AddSegment(L"FileZilla");
		}
		ret = tmp;
	}
	else {
		// Fall back to directory where the executable is
		DWORD c = GetModuleFileName(0, buffer, MAX_PATH * 2);
		if (c && c < MAX_PATH * 2) {
			std::wstring tmp;
			ret.SetPath(buffer, &tmp);
		}
	}
#else
	std::wstring cfg = TryDirectory(GetEnv(_T("XDG_CONFIG_HOME")), _T("filezilla/"), true);
	if (cfg.empty()) {
		cfg = TryDirectory(wxGetHomeDir(), _T(".config/filezilla/"), true);
	}
	if (cfg.empty()) {
		cfg = TryDirectory(wxGetHomeDir(), _T(".filezilla/"), true);
	}
	if (cfg.empty()) {
		cfg = TryDirectory(GetEnv(_T("XDG_CONFIG_HOME")), _T("filezilla/"), false);
	}
	if (cfg.empty()) {
		cfg = TryDirectory(wxGetHomeDir(), _T(".config/filezilla/"), false);
	}
	if (cfg.empty()) {
		cfg = TryDirectory(wxGetHomeDir(), _T(".filezilla/"), false);
	}
	ret.SetPath(cfg);
#endif
	return ret;
}
void CState::LocalDirCreated(const CLocalPath& path)
{
	if (!path.IsSubdirOf(m_localDir))
		return;

	wxString next_segment = path.GetPath().Mid(m_localDir.GetPath().Len());
	int pos = next_segment.Find(CLocalPath::path_separator);
	if (pos <= 0)
	{
		// Shouldn't ever come true
		return;
	}

	// Current local path is /foo/
	// Called with /foo/bar/baz/
	// -> Refresh /foo/bar/
	next_segment = next_segment.Left(pos);
	NotifyHandlers(STATECHANGE_LOCAL_REFRESH_FILE, next_segment);
}
예제 #8
0
void CRecursiveOperation::LinkIsNotDir()
{
	if (m_operationMode == recursive_none)
		return;

	wxASSERT(!m_dirsToVisit.empty());
	if (m_dirsToVisit.empty())
		return;

	CNewDir dir = m_dirsToVisit.front();
	m_dirsToVisit.pop_front();

	const CServer* pServer = m_pState->GetServer();
	if (!pServer)
	{
		NextOperation();
		return;
	}

	if (m_operationMode == recursive_delete)
	{
		if (!dir.subdir.empty())
		{
			std::list<wxString> files;
			files.push_back(dir.subdir);
			m_pState->m_pCommandQueue->ProcessCommand(new CDeleteCommand(dir.parent, files));
		}
		NextOperation();
		return;
	}
	else if (m_operationMode != recursive_list )
	{
		CLocalPath localPath = dir.localDir;
		wxString localFile = dir.subdir;
		if (m_operationMode != recursive_addtoqueue_flatten && m_operationMode != recursive_download_flatten)
			localPath.MakeParent();
		m_pQueue->QueueFile(m_operationMode == recursive_addtoqueue || m_operationMode == recursive_addtoqueue_flatten, true, dir.subdir, (dir.subdir == localFile) ? wxString() : localFile, localPath, dir.parent, *pServer, -1);
		m_pQueue->QueueFile_Finish(m_operationMode != recursive_addtoqueue);
	}

	NextOperation();
}
예제 #9
0
	virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def)
	{
		CListCtrlDropTarget::OnDragOver(x, y, def);

		if (def == wxDragError ||
			def == wxDragNone ||
			def == wxDragCancel)
		{
			ClearDropHighlight();
			return def;
		}

		if (m_pLocalListView->m_fileData.empty())
		{
			ClearDropHighlight();
			return wxDragNone;
		}

		const wxString& subdir = DoDisplayDropHighlight(wxPoint(x, y));

		CLocalPath dir = m_pLocalListView->m_pState->GetLocalDir();
		if (subdir == _T(""))
		{
			const CDragDropManager* pDragDropManager = CDragDropManager::Get();
			if (pDragDropManager && pDragDropManager->localParent == m_pLocalListView->m_dir)
				return wxDragNone;
		}
		else
		{
			if (!dir.ChangePath(subdir))
				return wxDragNone;
		}

		if (!dir.IsWriteable())
			return wxDragNone;

		if (def == wxDragLink)
			def = wxDragCopy;

		return def;
	}
void CRemoteRecursiveOperation::LinkIsNotDir()
{
	if (m_operationMode == recursive_none || recursion_roots_.empty()) {
		return;
	}

	auto & root = recursion_roots_.front();
	wxCHECK_RET(!root.m_dirsToVisit.empty(), _T("Empty dirs to visit"));

	recursion_root::new_dir dir = root.m_dirsToVisit.front();
	root.m_dirsToVisit.pop_front();

	const CServer* pServer = m_state.GetServer();
	if (!pServer) {
		NextOperation();
		return;
	}

	if (m_operationMode == recursive_delete) {
		if (!dir.subdir.empty()) {
			std::deque<std::wstring> files;
			files.push_back(dir.subdir);
			m_state.m_pCommandQueue->ProcessCommand(new CDeleteCommand(dir.parent, std::move(files)), CCommandQueue::recursiveOperation);
		}
		NextOperation();
		return;
	}
	else if (m_operationMode != recursive_list) {
		CLocalPath localPath = dir.localDir;
		std::wstring localFile = dir.subdir;
		if (m_operationMode != recursive_transfer_flatten) {
			localPath.MakeParent();
		}
		m_pQueue->QueueFile(!m_immediate, true, dir.subdir, (dir.subdir == localFile) ? std::wstring() : localFile, localPath, dir.parent, *pServer, -1);
		m_pQueue->QueueFile_Finish(m_immediate);
	}

	NextOperation();
}
예제 #11
0
파일: Options.cpp 프로젝트: Typz/FileZilla
void COptions::LoadGlobalDefaultOptions(std::map<std::string, unsigned int> const& nameOptionMap)
{
	CLocalPath const defaultsDir = wxGetApp().GetDefaultsDir();
	if (defaultsDir.empty())
		return;

	CXmlFile file(defaultsDir.GetPath() + _T("fzdefaults.xml"));
	if (!file.Load())
		return;

	TiXmlElement* pElement = file.GetElement();
	if (!pElement)
		return;

	pElement = pElement->FirstChildElement("Settings");
	if (!pElement)
		return;

	for (TiXmlElement* pSetting = pElement->FirstChildElement("Setting"); pSetting; pSetting = pSetting->NextSiblingElement("Setting")) {
		LoadOptionFromElement(pSetting, nameOptionMap, true);
	}
}
예제 #12
0
void CQueueStorage::Impl::ReadLocalPaths()
{
	if (!selectLocalPathQuery_)
		return;

	int res;
	do
	{
		res = sqlite3_step(selectLocalPathQuery_);
		if (res == SQLITE_ROW)
		{
			int64_t id = GetColumnInt64(selectLocalPathQuery_, path_table_column_names::id);
			wxString localPathRaw = GetColumnText(selectLocalPathQuery_, path_table_column_names::path);
			CLocalPath localPath;
			if (id > 0 && !localPathRaw.empty() && localPath.SetPath(localPathRaw))
				reverseLocalPaths_[id] = localPath;
		}
	}
	while (res == SQLITE_BUSY || res == SQLITE_ROW);

	sqlite3_reset(selectLocalPathQuery_);
}
예제 #13
0
int64_t CQueueStorage::Impl::SaveLocalPath(const CLocalPath& path)
{
	std::unordered_map<wxString, int64_t, wxStringHash, fast_equal>::const_iterator it = localPaths_.find(path.GetPath());
	if (it != localPaths_.end())
		return it->second;

	Bind(insertLocalPathQuery_, path_table_column_names::path, path.GetPath());

	int res;
	do {
		res = sqlite3_step(insertLocalPathQuery_);
	} while (res == SQLITE_BUSY);

	sqlite3_reset(insertLocalPathQuery_);

	if (res == SQLITE_DONE)
	{
		int64_t id = sqlite3_last_insert_rowid(db_);
		localPaths_[path.GetPath()] = id;
		return id;
	}

	return -1;
}
예제 #14
0
bool CLocalPath::IsSubdirOf(const CLocalPath &path) const
{
	if (empty() || path.empty())
		return false;

	if (path.m_path->size() > m_path->size())
		return false;

#ifdef FZ_WINDOWS
	if (fz::stricmp(*path.m_path, m_path->substr(0, path.m_path->size())))
		return false;
#else
	if (*path.m_path != m_path->substr(0, path.m_path->size()))
		return false;
#endif

	return true;
}
예제 #15
0
bool CLocalPath::IsSubdirOf(const CLocalPath &path) const
{
	if (empty() || path.empty())
		return false;

	if (path.m_path.Len() > m_path.Len())
		return false;

#ifdef __WXMSW__
	if (path.m_path.CmpNoCase(m_path.Left(path.m_path.Len())))
		return false;
#else
	if (path.m_path != m_path.Left(path.m_path.Len()))
		return false;
#endif

	return true;
}
예제 #16
0
bool CLocalPath::IsParentOf(const CLocalPath &path) const
{
	if (empty() || path.empty())
		return false;

	if (path.m_path->Len() < m_path->Len())
		return false;

#ifdef __WXMSW__
	if (m_path->CmpNoCase(path.m_path->Left(m_path->Len())))
		return false;
#else
	if (*m_path != path.m_path->Left(m_path->Len()))
		return false;
#endif

	return true;
}
예제 #17
0
bool CLocalPath::IsParentOf(const CLocalPath &path) const
{
	if (empty() || path.empty()) {
		return false;
	}

	if (path.m_path->size() < m_path->size()) {
		return false;
	}

#ifdef FZ_WINDOWS
	if (fz::stricmp(*m_path, path.m_path->substr(0, m_path->size())))
		return false;
#else
	if (*m_path != path.m_path->substr(0, m_path->size()))
		return false;
#endif

	return true;
}
예제 #18
0
CLocalPath COptions::InitSettingsDir()
{
	CLocalPath p;

	std::wstring dir = GetOption(OPTION_DEFAULT_SETTINGSDIR);
	if (!dir.empty()) {
		dir = ExpandPath(dir);
		p.SetPath(wxGetApp().GetDefaultsDir().GetPath());
		p.ChangePath(dir);
	}
	else {
		p = GetUnadjustedSettingsDir();
	}

	if (!p.empty() && !p.Exists()) {
		wxFileName::Mkdir(p.GetPath(), 0700, wxPATH_MKDIR_FULL);
	}

	SetOption(OPTION_DEFAULT_SETTINGSDIR, p.GetPath());

	return p;
}
예제 #19
0
파일: Options.cpp 프로젝트: Typz/FileZilla
CLocalPath COptions::InitSettingsDir()
{
	CLocalPath p;

	wxString dir(GetOption(OPTION_DEFAULT_SETTINGSDIR));
	if (!dir.empty()) {
		wxStringTokenizer tokenizer(dir, _T("/\\"), wxTOKEN_RET_EMPTY_ALL);
		dir = _T("");
		while (tokenizer.HasMoreTokens()) {
			wxString token = tokenizer.GetNextToken();
			if (!token.empty() && token[0] == '$') {
				if (token.size() > 1 && token[1] == '$')
					token = token.Mid(1);
				else {
					token = GetEnv(token.Mid(1));
				}
			}
			dir += token;
			const wxChar delimiter = tokenizer.GetLastDelimiter();
			if (delimiter)
				dir += delimiter;
		}

		p.SetPath(wxGetApp().GetDefaultsDir().GetPath());
		p.ChangePath(dir);
	}
	else {
		p = GetUnadjustedSettingsDir();
	}

	if (!p.empty() && !p.Exists())
		wxFileName::Mkdir( p.GetPath(), 0700, wxPATH_MKDIR_FULL );

	SetOption(OPTION_DEFAULT_SETTINGSDIR, p.GetPath());

	return p;
}
예제 #20
0
void CState::HandleDroppedFiles(const wxFileDataObject* pFileDataObject, const CLocalPath& path, bool copy)
{
	const wxArrayString &files = pFileDataObject->GetFilenames();
	if (!files.Count())
		return;

#ifdef __WXMSW__
	int len = 1;

	for (unsigned int i = 0; i < files.Count(); i++)
		len += files[i].Len() + 1;

	// SHFILEOPSTRUCT's pTo and pFrom accept null-terminated lists
	// of null-terminated filenames.
	wxChar* from = new wxChar[len];
	wxChar* p = from;
	for (unsigned int i = 0; i < files.Count(); i++)
	{
		wxStrcpy(p, files[i]);
		p += files[i].Len() + 1;
	}
	*p = 0; // End of list

	wxChar* to = new wxChar[path.GetPath().Len() + 2];
	wxStrcpy(to, path.GetPath());
	to[path.GetPath().Len() + 1] = 0; // End of list

	SHFILEOPSTRUCT op = {0};
	op.pFrom = from;
	op.pTo = to;
	op.wFunc = copy ? FO_COPY : FO_MOVE;
	op.hwnd = (HWND)m_pMainFrame->GetHandle();
	SHFileOperation(&op);

	delete [] to;
	delete [] from;
#else
	for (unsigned int i = 0; i < files.Count(); i++)
	{
		const wxString& file(files[i]);

		wxLongLong size;
		bool is_link;
		CLocalFileSystem::local_fileType type = CLocalFileSystem::GetFileInfo(file, is_link, &size, 0, 0);
		if (type == CLocalFileSystem::file)
		{
			wxString name;
			CLocalPath sourcePath(file, &name);
			if (name.empty())
				continue;
			if (copy)
				wxCopyFile(file, path.GetPath() + name);
			else
				wxRenameFile(file, path.GetPath() + name);
		}
		else if (type == CLocalFileSystem::dir)
		{
			if (copy)
				RecursiveCopy(CLocalPath(file), path);
			else
			{
				CLocalPath sourcePath(file);
				if (!sourcePath.HasParent())
					continue;
				wxRenameFile(file, path.GetPath() + sourcePath.GetLastSegment());
			}
		}
	}
#endif

	RefreshLocal();
}
예제 #21
0
	virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
	{
		if (def == wxDragError ||
			def == wxDragNone ||
			def == wxDragCancel)
			return def;

		if (m_pLocalListView->m_fileData.empty())
			return wxDragError;

		if (def != wxDragCopy && def != wxDragMove)
			return wxDragError;

		CDragDropManager* pDragDropManager = CDragDropManager::Get();
		if (pDragDropManager)
			pDragDropManager->pDropTarget = m_pLocalListView;

		wxString subdir;
		int flags;
		int hit = m_pLocalListView->HitTest(wxPoint(x, y), flags, 0);
		if (hit != -1 && (flags & wxLIST_HITTEST_ONITEM))
		{
			const CLocalFileData* const data = m_pLocalListView->GetData(hit);
			if (data && data->dir)
				subdir = data->name;
		}

		CLocalPath dir = m_pLocalListView->m_pState->GetLocalDir();
		if (subdir != _T(""))
		{
			if (!dir.ChangePath(subdir))
				return wxDragError;
		}

		if (!dir.IsWriteable())
			return wxDragError;

		if (!GetData())
			return wxDragError;

		if (m_pDataObject->GetReceivedFormat() == m_pFileDataObject->GetFormat())
			m_pLocalListView->m_pState->HandleDroppedFiles(m_pFileDataObject, dir, def == wxDragCopy);
		else
		{
			if (m_pRemoteDataObject->GetProcessId() != (int)wxGetProcessId())
			{
				wxMessageBoxEx(_("Drag&drop between different instances of FileZilla has not been implemented yet."));
				return wxDragNone;
			}

			if (!m_pLocalListView->m_pState->GetServer() || !m_pRemoteDataObject->GetServer().EqualsNoPass(*m_pLocalListView->m_pState->GetServer()))
			{
				wxMessageBoxEx(_("Drag&drop between different servers has not been implemented yet."));
				return wxDragNone;
			}

			if (!m_pLocalListView->m_pState->DownloadDroppedFiles(m_pRemoteDataObject, dir))
				return wxDragNone;
		}

		return def;
	}
void CState::HandleDroppedFiles(const wxFileDataObject* pFileDataObject, const CLocalPath& path, bool copy)
{
	const wxArrayString &files = pFileDataObject->GetFilenames();
	if (!files.Count())
		return;

#ifdef __WXMSW__
	int len = 1;

	for (unsigned int i = 0; i < files.Count(); i++)
		len += files[i].Len() + 1;

	// SHFILEOPSTRUCT's pTo and pFrom accept null-terminated lists
	// of null-terminated filenames.
	wxChar* from = new wxChar[len];
	wxChar* p = from;
	for (unsigned int i = 0; i < files.Count(); i++)
	{
		wxStrcpy(p, files[i]);
		p += files[i].Len() + 1;
	}
	*p = 0; // End of list

	wxChar* to = new wxChar[path.GetPath().Len() + 2];
	wxStrcpy(to, path.GetPath());
	to[path.GetPath().Len() + 1] = 0; // End of list

	SHFILEOPSTRUCT op = {0};
	op.pFrom = from;
	op.pTo = to;
	op.wFunc = copy ? FO_COPY : FO_MOVE;
	op.hwnd = (HWND)m_pMainFrame->GetHandle();
	SHFileOperation(&op);

	delete [] to;
	delete [] from;
#else
	wxString error;
	for (unsigned int i = 0; i < files.Count(); i++)
	{
		const wxString& file(files[i]);

		int64_t size;
		bool is_link;
		CLocalFileSystem::local_fileType type = CLocalFileSystem::GetFileInfo(file, is_link, &size, 0, 0);
		if (type == CLocalFileSystem::file)
		{
			wxString name;
			CLocalPath sourcePath(file, &name);
			if (name.empty())
				continue;
			wxString target = path.GetPath() + name;
			if (file == target)
				continue;

			if (copy)
				wxCopyFile(file, target);
			else
				wxRenameFile(file, target);
		}
		else if (type == CLocalFileSystem::dir)
		{
			CLocalPath sourcePath(file);
			if (sourcePath == path || sourcePath.GetParent() == path)
				continue;
			if (sourcePath.IsParentOf(path))
			{
				error = _("A directory cannot be dragged into one of its subdirectories.");
				continue;
			}

			if (copy)
				RecursiveCopy(sourcePath, path);
			else
			{
				if (!sourcePath.HasParent())
					continue;
				wxRenameFile(file, path.GetPath() + sourcePath.GetLastSegment());
			}
		}
	}
	if (!error.empty())
		wxMessageBoxEx(error, _("Could not complete operation"));
#endif

	RefreshLocal();
}
bool CState::SetLocalDir(CLocalPath const& dir, wxString *error, bool rememberPreviousSubdir)
{
	if (m_sync_browse.is_changing) {
		wxMessageBoxEx(_T("Cannot change directory, there already is a synchronized browsing operation in progress."), _("Synchronized browsing"));
		return false;
	}

	if (!dir.Exists(error))
		return false;

	if (!m_sync_browse.local_root.empty()) {
		wxASSERT(m_pServer);

		if (dir != m_sync_browse.local_root && !dir.IsSubdirOf(m_sync_browse.local_root)) {
			wxString msg = wxString::Format(_("The local directory '%s' is not below the synchronization root (%s).\nDisable synchronized browsing and continue changing the local directory?"),
					dir.GetPath(),
					m_sync_browse.local_root.GetPath());
			if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
				return false;
			SetSyncBrowse(false);
		}
		else if (!IsRemoteIdle()) {
			wxString msg(_("A remote operation is in progress and synchronized browsing is enabled.\nDisable synchronized browsing and continue changing the local directory?"));
			if (wxMessageBoxEx(msg, _("Synchronized browsing"), wxICON_QUESTION | wxYES_NO) != wxYES)
				return false;
			SetSyncBrowse(false);
		}
		else {
			CServerPath remote_path = GetSynchronizedDirectory(dir);
			if (remote_path.empty()) {
				SetSyncBrowse(false);
				wxString msg = wxString::Format(_("Could not obtain corresponding remote directory for the local directory '%s'.\nSynchronized browsing has been disabled."),
					dir.GetPath());
				wxMessageBoxEx(msg, _("Synchronized browsing"));
				return false;
			}

			m_sync_browse.is_changing = true;
			m_sync_browse.compare = m_pComparisonManager->IsComparing();
			CListCommand *pCommand = new CListCommand(remote_path);
			m_pCommandQueue->ProcessCommand(pCommand);

			return true;
		}
	}

	if (dir == m_localDir.GetParent() && rememberPreviousSubdir) {
#ifdef __WXMSW__
		if (dir.GetPath() == _T("\\")) {
			m_previouslyVisitedLocalSubdir = m_localDir.GetPath();
			m_previouslyVisitedLocalSubdir.RemoveLast();
		}
		else
#endif
			m_previouslyVisitedLocalSubdir = m_localDir.GetLastSegment();
	}
	else
		m_previouslyVisitedLocalSubdir = _T("");


	m_localDir = dir;

	COptions::Get()->SetOption(OPTION_LASTLOCALDIR, m_localDir.GetPath());

	NotifyHandlers(STATECHANGE_LOCAL_DIR);

	return true;
}