Converted project to C++.

This commit is contained in:
2018-08-06 21:37:16 +03:00
parent 144c3e3e25
commit d85c366212
104 changed files with 6224 additions and 239448 deletions

View File

@ -1,2 +0,0 @@
from .recent_project import RecentProject
from .project import Project, ProjectItem, ItemType

View File

@ -1,2 +0,0 @@
class CompositionClip(object):
pass

95
model/project.cpp Normal file
View File

@ -0,0 +1,95 @@
#include <pugixml.hpp>
#include "project.h"
namespace Ember
{
Project::Project(boost::filesystem::path projectFilePath)
: m_path(projectFilePath),
m_name(),
m_bitsPerChannel(8),
m_audioSampleRate(48000),
m_rootItem(projectFilePath.parent_path(), nullptr, this)
{
}
boost::filesystem::path Project::path() const
{
return m_path;
}
std::string Project::name() const
{
return m_name;
}
int Project::bitsPerChannel() const
{
return m_bitsPerChannel;
}
int Project::audioSampleRate() const
{
return m_audioSampleRate;
}
ProjectItem& Project::rootItem()
{
return m_rootItem;
}
void Project::setName(const std::string &name)
{
m_name = name;
}
void Project::setBitsPerChannel(int bitsPerChannel)
{
m_bitsPerChannel = bitsPerChannel;
}
void Project::setAudioSampleRate(int audioSampleRate)
{
m_audioSampleRate = audioSampleRate;
}
void Project::load()
{
pugi::xml_document doc;
if (!doc.load_file(m_path.c_str()))
{
// TODO: proper error handlign
throw 0;
}
pugi::xml_node root = doc.document_element();
// Get name
pugi::xml_attribute attr;
if ((attr = root.attribute("name")))
m_name = attr.as_string();
// Get other properties
if ((attr = root.attribute("bitsPerChannel")))
m_bitsPerChannel = attr.as_int();
if ((attr = root.attribute("audioSampleRate")))
m_audioSampleRate = attr.as_int();
}
void Project::save()
{
pugi::xml_document doc;
doc.append_child(pugi::node_declaration);
auto proj = doc.append_child("project");
proj.append_attribute("name").set_value(m_name.c_str());
proj.append_attribute("bitsPerChannel").set_value(m_bitsPerChannel);
proj.append_attribute("audioSampleRate").set_value(m_audioSampleRate);
doc.save_file(m_path.string().c_str());
}
}

57
model/project.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef PROJECT_H
#define PROJECT_H
#include <string>
#include <time.h>
#include <boost/filesystem.hpp>
#include "projectitem.h"
namespace Ember
{
class Project
{
public:
Project(boost::filesystem::path projectFilePath);
// Getters
boost::filesystem::path path() const;
std::string name() const;
int bitsPerChannel() const;
int audioSampleRate() const;
ProjectItem& rootItem();
// Setters
void setName(const std::string &name);
void setBitsPerChannel(int bitsPerChannel);
void setAudioSampleRate(int audioSampleRate);
// Actions
void load();
void save();
private:
boost::filesystem::path m_path;
// Details (that will be stored in project file)
std::string m_name;
int m_bitsPerChannel = 8;
int m_audioSampleRate = 48000;
// Items
ProjectItem m_rootItem;
};
struct RecentProject
{
std::string name;
boost::filesystem::path path;
time_t access;
bool pinned;
};
}
#endif // PROJECT_H

View File

@ -1,74 +0,0 @@
import os
from enum import Enum
from typing import List
class ItemType(Enum):
MISSING = 0
DIRECTORY = 1
IMAGE = 2
AUDIO = 3
VIDEO = 4
SUBTITLES = 5
PROJECT = 6
COMPOSITION = 7
SEQUENCE = 8
UNKNOWN = 1000
class ProjectItem(object):
def __init__(self, name : str, project : "Project", storage : "ProjectStorage", parent : "ProjectItem" = None):
self.__storage = storage
self.name = name
self.project = project
self.parent = parent
self.__type : ItemType = None
self.__children : list = None
"""
Gets the path relative to the project directory.
Returns:
path relative to the project root folder.
"""
def path(self) -> str:
if self.parent:
return os.path.join(self.parent.path(), self.name)
return self.name
"""
Gets the absolute path to this project item.
"""
def absolutePath(self) -> str:
return os.path.join(self.project.rootDir, self.path())
"""
Gets the type of this project item.
"""
def itemType(self) -> str:
if self.__type is None:
self.__type = self.__storage.itemType(self)
return self.__type
"""
Gets the children project items.
"""
def children(self) -> List["ProjectItem"]:
if self.__children is None:
self.__children = list(self.__storage.itemChildren(self))
return self.__children
class Project(object):
def __init__(self, path : str, storage : "ProjectStorage"):
self.__storage = storage
self.projectFile : str = path
self.rootDir : str = None
self.videoBitsPerChannel : int = 8
self.videoColorSpace : str = None
self.audioSampleRate : int = 48000
self.__items : List[ProjectItem] = None
def items(self) -> List[ProjectItem]:
if self.__items is None:
self.__items = list(self.__storage.projectItems(self))
return self.__items

137
model/projectitem.cpp Normal file
View File

@ -0,0 +1,137 @@
#include <algorithm>
#include <boost/filesystem.hpp>
#include <properties/config.h>
#include "project.h"
#include "projectitem.h"
namespace Ember
{
ProjectItem::ProjectItem(boost::filesystem::path path, ProjectItem* parent, Project* project)
: m_path(path),
m_type(),
m_typeLoaded(false),
m_parent(parent),
m_children(),
m_childrenLoaded(false),
m_project(project)
{
}
std::string ProjectItem::name() const
{
return m_path.filename().string();
}
ProjectItem::ProjectItemType ProjectItem::type()
{
if (!m_typeLoaded)
{
if (boost::filesystem::is_directory(m_path))
{
m_type = ProjectItemType::DIRECTORY;
}
else if (boost::filesystem::exists(m_path))
{
std::string ext = m_path.extension().string();
if (ext == ".png" || ext == ".jpg" || ext == ".bmp" || ext == ".jpeg")
m_type = ProjectItemType::IMAGE;
else if (ext == ".mp3" || ext == ".ogg" || ext == ".wav")
m_type = ProjectItemType::AUDIO;
else if (ext == ".avi" || ext == ".mp4" || ext == ".wmv")
m_type = ProjectItemType::VIDEO;
else if (ext == ".srt")
m_type = ProjectItemType::SUBTITLES;
else if (ext == EMBER_PROJECT_EXTENSION)
m_type = ProjectItemType::PROJECT;
else if (ext == EMBER_COMPOSITION_EXTENSION)
m_type = ProjectItemType::COMPOSITION;
else if (ext == EMBER_SEQUENCE_EXTENSION)
m_type = ProjectItemType::SEQUENCE;
else m_type = ProjectItemType::UNKNOWN;
}
else
{
m_type = ProjectItemType::MISSING;
}
m_typeLoaded = true;
}
return m_type;
}
ProjectItem *ProjectItem::parent() const
{
return m_parent;
}
Project *ProjectItem::project() const
{
return m_project;
}
const std::vector<ProjectItem *>& ProjectItem::children()
{
if (!m_childrenLoaded)
{
if (type() == ProjectItemType::DIRECTORY)
{
for (auto&& entry : boost::filesystem::directory_iterator(m_path))
{
ProjectItem* child = new ProjectItem(entry.path(), this, m_project);
m_children.push_back(child);
}
}
m_childrenLoaded = true;
}
return m_children;
}
boost::filesystem::path ProjectItem::path() const
{
return m_path;
}
void ProjectItem::rename(const std::string &name)
{
auto newPath = m_path.parent_path().append(name);
boost::filesystem::rename(m_path, newPath);
}
void ProjectItem::move(ProjectItem *newParent)
{
auto newPath = newParent->path().append(name());
boost::filesystem::rename(m_path, newPath);
// Update parenting
if (m_parent)
m_parent->unparentChild(this);
newParent->m_children.push_back(this);
}
void ProjectItem::unlink()
{
boost::filesystem::remove(m_path);
// Update parenting
if (m_parent)
delete m_parent->unparentChild(this);
}
ProjectItem *ProjectItem::unparentChild(ProjectItem *child)
{
auto it = std::find(m_children.begin(), m_children.end(), child);
if (it != m_children.end())
m_parent->m_children.erase(it);
return child;
}
}

105
model/projectitem.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef PROJECTITEM_H
#define PROJECTITEM_H
#include <string>
#include <boost/filesystem.hpp>
namespace Ember
{
class Project;
class ProjectItem
{
public:
enum ProjectItemType
{
UNKNOWN,
MISSING,
DIRECTORY,
IMAGE,
AUDIO,
VIDEO,
SUBTITLES,
PROJECT,
COMPOSITION,
SEQUENCE
};
/**
* @brief ProjectItem constructor
* @param name Name corresponding to file on disk
* @param parent Parent project item
* @param project Assigned project
*/
ProjectItem(boost::filesystem::path path, ProjectItem* parent, Project* project);
// Getters
/**
* @brief Gets the name of the item
* @return Name
*/
std::string name() const;
/**
* @brief Gets the type of the item.
* @return Type of item
*/
ProjectItemType type();
/**
* @brief Gets the parent project item.
* @return Parent item
*/
ProjectItem *parent() const;
/**
* @brief Gets the parent project
* @return Parent project
*/
Project *project() const;
/**
* @brief Gets a list of children. If not a directory, the list will be empty.
* @return Vector of children.
*/
const std::vector<ProjectItem *>& children();
/**
* @brief Gets the path of this project item
* @return
*/
boost::filesystem::path path() const;
// Action
/**
* @brief Sets the name of the item. Will result in a disk rename.
* @param name New name
*/
void rename(const std::string &name);
/**
* @brief Sets the parent project item. Will result in a disk move.
* @param newParent New parent
*/
void move(ProjectItem *newParent);
/**
* @brief Delete from the disk. 'this' object is DELETED!
* TODO: recycle bin or permanent delete?
*/
void unlink();
private:
ProjectItem* unparentChild(ProjectItem* child);
boost::filesystem::path m_path;
ProjectItemType m_type;
bool m_typeLoaded;
ProjectItem* m_parent;
std::vector<ProjectItem*> m_children;
bool m_childrenLoaded;
Project* m_project;
};
}
#endif // PROJECTITEM_H

View File

@ -1,60 +0,0 @@
import time
from typing import List
class RecentProject(object):
DICT_FIELDS = [ 'path', 'name', 'dateAccessed', 'pinned' ]
"""
Creates new instance of RecentProject.
Args:
name: name of the project
path: path to the project
dateAccessed: date (unix time) when project was last accessed
pinned: the project is pinned by the user
Remarks:
If dateAccessed = None, it will be set to the current date and time.
"""
def __init__(self, name: str, path: str, dateAccessed : int = None, pinned : bool = False):
self.name = name
self.path = path
self.dateAccessed = dateAccessed
self.pinned = pinned
if (self.dateAccessed is None):
self.dateAccessed = int(time.time())
"""
Creates new instance of RecentProject from a dictionary.
If the dateAccessed and pinned fields are strings, they are parsed.
Raises:
ValueError if date cannot be parsed.
"""
@staticmethod
def fromDictionary(data : dict) -> 'RecentProject':
name = data['name']
path = data['path']
dateAccessed = data['dateAccessed']
pinned = data['pinned']
if isinstance(dateAccessed, str):
dateAccessed = int(dateAccessed)
if isinstance(pinned, str):
pinned = pinned.lower() in [ 'yes', 'y', 'true', '1', 'on' ]
return RecentProject(name, path, dateAccessed, pinned)
"""
Serialize to dictionary.
"""
def toDictionary(self) -> dict:
return {
"name" : self.name,
"path" : self.path,
"dateAccessed" : self.dateAccessed,
"pinned" : self.pinned
}