started on #83 and added open recent menu
This commit is contained in:
@@ -351,13 +351,31 @@ void ExportDialog::on_pushButton_clicked()
|
||||
case FORMAT_GIF:
|
||||
ext = "gif";
|
||||
break;
|
||||
case FORMAT_IMG:
|
||||
// ext_name = "";
|
||||
// ext = "";
|
||||
// ext is determined from codec, but we prevent the switch from going to 'default' here
|
||||
qDebug() << "[INFO] Image export not implemented yet";
|
||||
QMessageBox::information(this, "Image sequence support coming soon", "Sorry, image sequence exporting is currently unsupported. Check back soon (or hound GitHub issue #83).", QMessageBox::Ok);
|
||||
return;
|
||||
case FORMAT_IMG:
|
||||
switch (format_vcodecs.at(ui->vcodecCombobox->currentIndex())) {
|
||||
case AV_CODEC_ID_BMP:
|
||||
ext = "bmp";
|
||||
break;
|
||||
case AV_CODEC_ID_MJPEG:
|
||||
ext = "jpg";
|
||||
break;
|
||||
case AV_CODEC_ID_JPEG2000:
|
||||
ext = "jp2";
|
||||
break;
|
||||
case AV_CODEC_ID_PSD:
|
||||
ext = "psd";
|
||||
break;
|
||||
case AV_CODEC_ID_PNG:
|
||||
ext = "png";
|
||||
break;
|
||||
case AV_CODEC_ID_TIFF:
|
||||
ext = "tif";
|
||||
break;
|
||||
default:
|
||||
qDebug() << "[ERROR] Invalid codec selection for an image sequence";
|
||||
QMessageBox::critical(this, "Invalid codec", "Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers.", QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case FORMAT_MP3:
|
||||
ext = "mp3";
|
||||
|
||||
@@ -94,12 +94,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(ui->menu_View, SIGNAL(aboutToShow()), this, SLOT(viewMenu_About_To_Be_Shown()));
|
||||
connect(ui->menu_Tools, SIGNAL(aboutToShow()), this, SLOT(toolMenu_About_To_Be_Shown()));
|
||||
connect(ui->menuEdit, SIGNAL(aboutToShow()), this, SLOT(editMenu_About_To_Be_Shown()));
|
||||
connect(ui->menu_File, SIGNAL(aboutToShow()), this, SLOT(fileMenu_About_To_Be_Shown()));
|
||||
|
||||
QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
if (!data_dir.isEmpty()) {
|
||||
QDir dir(data_dir);
|
||||
dir.mkpath(".");
|
||||
if (dir.exists()) {
|
||||
// detect auto-recovery file
|
||||
autorecovery_filename = data_dir + "/autorecovery.ove";
|
||||
if (QFile::exists(autorecovery_filename)) {
|
||||
if (QMessageBox::question(NULL, "Auto-recovery", "Olive didn't close properly and an autorecovery file was detected. Would you like to open it?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
||||
@@ -110,6 +112,22 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
autorecovery_timer.setInterval(60000);
|
||||
QObject::connect(&autorecovery_timer, SIGNAL(timeout()), this, SLOT(autorecover_interval()));
|
||||
autorecovery_timer.start();
|
||||
|
||||
// search for open recents list
|
||||
recent_proj_file = data_dir + "/recents";
|
||||
QFile f(recent_proj_file);
|
||||
if (f.exists() && f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream text_stream(&f);
|
||||
while (true) {
|
||||
QString line = text_stream.readLine();
|
||||
if (line.isNull()) {
|
||||
break;
|
||||
} else {
|
||||
recent_projects.append(line);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,3 +574,27 @@ void MainWindow::on_actionFolder_triggered()
|
||||
{
|
||||
panel_project->new_folder();
|
||||
}
|
||||
|
||||
void MainWindow::fileMenu_About_To_Be_Shown() {
|
||||
if (recent_projects.size() > 0) {
|
||||
ui->menuOpen_Recent->clear();
|
||||
ui->menuOpen_Recent->setEnabled(true);
|
||||
for (int i=0;i<recent_projects.size();i++) {
|
||||
QAction* action = ui->menuOpen_Recent->addAction(recent_projects.at(i));
|
||||
action->setData(i);
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(load_recent_project()));
|
||||
}
|
||||
ui->menuOpen_Recent->addSeparator();
|
||||
QAction* clear_action = ui->menuOpen_Recent->addAction("Clear Recent List");
|
||||
connect(clear_action, SIGNAL(triggered()), panel_project, SLOT(clear_recent_projects()));
|
||||
} else {
|
||||
ui->menuOpen_Recent->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::load_recent_project() {
|
||||
if (can_close_project()) {
|
||||
project_url = recent_projects.at(static_cast<QAction*>(sender())->data().toInt());
|
||||
panel_project->load_project();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -18,7 +18,7 @@ class MainWindow : public QMainWindow
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *);
|
||||
@@ -146,6 +146,10 @@ private slots:
|
||||
|
||||
void editMenu_About_To_Be_Shown();
|
||||
|
||||
void fileMenu_About_To_Be_Shown();
|
||||
|
||||
void load_recent_project();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
void setup_layout();
|
||||
|
||||
@@ -40,8 +40,14 @@
|
||||
<addaction name="actionSequence"/>
|
||||
<addaction name="actionFolder"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuOpen_Recent">
|
||||
<property name="title">
|
||||
<string>Open Recent</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menu_New"/>
|
||||
<addaction name="action_Open_Project"/>
|
||||
<addaction name="menuOpen_Recent"/>
|
||||
<addaction name="action_Save_Project"/>
|
||||
<addaction name="actionSave_Project_As"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -589,6 +595,11 @@
|
||||
<string>Folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClear_Recent_List">
|
||||
<property name="text">
|
||||
<string>Clear Recent List</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
|
||||
+51
-184
@@ -12,6 +12,7 @@
|
||||
#include "project/effect.h"
|
||||
#include "effects/transition.h"
|
||||
#include "io/previewgenerator.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QString>
|
||||
@@ -30,8 +31,12 @@ extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
#define MAXIMUM_RECENT_PROJECTS 10
|
||||
|
||||
bool project_changed = false;
|
||||
QString project_url = "";
|
||||
QStringList recent_projects;
|
||||
QString recent_proj_file;
|
||||
|
||||
Project::Project(QWidget *parent) :
|
||||
QDockWidget(parent),
|
||||
@@ -647,190 +652,6 @@ void Project::load_project() {
|
||||
cont = load_worker(file, stream, MEDIA_TYPE_SEQUENCE);
|
||||
}
|
||||
|
||||
/*int state = LOAD_STATE_IDLE;
|
||||
while (!error && !stream.atEnd()) {
|
||||
stream.readNext();
|
||||
switch (state) {
|
||||
case LOAD_STATE_IDLE:
|
||||
if (stream.isStartElement()) {
|
||||
if (stream.name() == "footage") {
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name() == "id") {
|
||||
temp_media_id = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
state = LOAD_STATE_FOOTAGE;
|
||||
} else if (stream.name() == "sequence") {
|
||||
temp_seq = new Sequence();
|
||||
state = LOAD_STATE_SEQUENCE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOAD_STATE_FOOTAGE:
|
||||
if (stream.isEndElement() && stream.name() == "footage") {
|
||||
Media* m = import_file(temp_url);
|
||||
if (m == NULL) {
|
||||
error = (QMessageBox::warning(this, "Source load error", "Couldn't load source file '" + temp_url + "'. This is unsupported and may lead to crashes. Do you wish to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No);
|
||||
} else {
|
||||
m->save_id = temp_media_id;
|
||||
m->name = temp_name;
|
||||
temp_media_list.append(m);
|
||||
}
|
||||
state = LOAD_STATE_IDLE;
|
||||
} else if (stream.isStartElement()) {
|
||||
if (stream.name() == "name") {
|
||||
stream.readNext();
|
||||
temp_name = stream.text().toString();
|
||||
} else if (stream.name() == "url") {
|
||||
stream.readNext();
|
||||
temp_url = stream.text().toString();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOAD_STATE_SEQUENCE:
|
||||
if (stream.isEndElement() && stream.name() == "sequence") {
|
||||
// correct IDs
|
||||
for (int i=0;i<temp_seq->clip_count();i++) {
|
||||
Clip* clip = temp_seq->get_clip(i);
|
||||
|
||||
// correct IDs in linked clips
|
||||
for (int j=0;j<clip->linked.size();j++) {
|
||||
bool found = false;
|
||||
for (int k=0;k<temp_seq->clip_count();k++) {
|
||||
if (temp_seq->get_clip(k)->load_id == clip->linked.at(j)) {
|
||||
clip->linked[j] = k;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (QMessageBox::warning(this, "Corrupt clip link", "Project contains a non-existent clip link. It may be corrupt. Would you like to load it anyway?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
||||
clip->linked.removeAt(j);
|
||||
} else {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp_seq->reset_undo();
|
||||
new_sequence(temp_seq, false);
|
||||
state = LOAD_STATE_IDLE;
|
||||
} else if (stream.isStartElement()) {
|
||||
if (stream.name() == "name") {
|
||||
stream.readNext();
|
||||
temp_seq->name = stream.text().toString();
|
||||
} else if (stream.name() == "width") {
|
||||
stream.readNext();
|
||||
temp_seq->width = stream.text().toInt();
|
||||
} else if (stream.name() == "height") {
|
||||
stream.readNext();
|
||||
temp_seq->height = stream.text().toInt();
|
||||
} else if (stream.name() == "framerate") {
|
||||
stream.readNext();
|
||||
temp_seq->frame_rate = stream.text().toFloat();
|
||||
} else if (stream.name() == "afreq") {
|
||||
stream.readNext();
|
||||
temp_seq->audio_frequency = stream.text().toInt();
|
||||
} else if (stream.name() == "alayout") {
|
||||
stream.readNext();
|
||||
temp_seq->audio_layout = stream.text().toInt();
|
||||
} else if (stream.name() == "clip") {
|
||||
temp_clip = new Clip();
|
||||
temp_clip->sequence = temp_seq;
|
||||
state = LOAD_STATE_CLIP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOAD_STATE_CLIP:
|
||||
if (stream.isEndElement() && stream.name() == "clip") {
|
||||
temp_seq->add_clip(temp_clip);
|
||||
state = LOAD_STATE_SEQUENCE;
|
||||
} else if (stream.isStartElement()) {
|
||||
if (stream.name() == "name") {
|
||||
stream.readNext();
|
||||
temp_clip->name = stream.text().toString();
|
||||
} else if (stream.name() == "id") {
|
||||
stream.readNext();
|
||||
temp_clip->load_id = stream.text().toInt();
|
||||
} else if (stream.name() == "clipin") {
|
||||
stream.readNext();
|
||||
temp_clip->clip_in = stream.text().toInt();
|
||||
} else if (stream.name() == "in") {
|
||||
stream.readNext();
|
||||
temp_clip->timeline_in = stream.text().toInt();
|
||||
} else if (stream.name() == "out") {
|
||||
stream.readNext();
|
||||
temp_clip->timeline_out = stream.text().toInt();
|
||||
} else if (stream.name() == "track") {
|
||||
stream.readNext();
|
||||
temp_clip->track = stream.text().toInt();
|
||||
} else if (stream.name() == "opening") {
|
||||
stream.readNext();
|
||||
temp_clip->opening_transition = create_transition(stream.text().toInt(), temp_clip);
|
||||
} else if (stream.name() == "closing") {
|
||||
stream.readNext();
|
||||
temp_clip->closing_transition = create_transition(stream.text().toInt(), temp_clip);
|
||||
} else if (stream.name() == "color") {
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name().toString() == QLatin1String("r")) {
|
||||
temp_clip->color_r = attr.value().toInt();
|
||||
} else if (attr.name().toString() == QLatin1String("g")) {
|
||||
temp_clip->color_g = attr.value().toInt();
|
||||
} else if (attr.name().toString() == QLatin1String("b")) {
|
||||
temp_clip->color_b = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
} else if (stream.name() == "media") {
|
||||
stream.readNext();
|
||||
for (int i=0;i<temp_media_list.size();i++) {
|
||||
Media* m = temp_media_list.at(i);
|
||||
if (m->save_id == stream.text().toInt()) {
|
||||
temp_clip->media = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (stream.name() == "stream") {
|
||||
stream.readNext();
|
||||
int stream_index = stream.text().toInt();
|
||||
if (temp_clip->media != NULL) {
|
||||
temp_clip->media_stream = temp_clip->media->get_stream_from_file_index(stream_index);
|
||||
if (temp_clip->media_stream == NULL) {
|
||||
if (QMessageBox::warning(this, "Source changed", "Source file '" + temp_clip->media->url + "' appears to have changed since last saving the project. This is unsupported and may lead to crashes. Do you wish to continue?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (stream.name() == "linked") {
|
||||
state = LOAD_STATE_CLIP_LINKS;
|
||||
} else if (stream.name() == "effect") {
|
||||
int effect_id = -1;
|
||||
for (int j=0;j<stream.attributes().size();j++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(j);
|
||||
if (attr.name().toString() == QLatin1String("id")) {
|
||||
effect_id = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
if (effect_id != -1) {
|
||||
Effect* e = create_effect(effect_id, temp_clip);
|
||||
e->load(&stream);
|
||||
temp_clip->effects.append(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LOAD_STATE_CLIP_LINKS:
|
||||
if (stream.name() == "linked" && stream.isEndElement()) {
|
||||
state = LOAD_STATE_CLIP;
|
||||
} else if (stream.isStartElement() && stream.name() == "link") {
|
||||
stream.readNext();
|
||||
temp_clip->linked.append(stream.text().toInt());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
if (!cont) {
|
||||
QMessageBox::critical(this, "Project Load Error", "Error loading project: " + error_str, QMessageBox::Ok);
|
||||
} else if (stream.hasError()) {
|
||||
@@ -845,6 +666,10 @@ void Project::load_project() {
|
||||
} else {
|
||||
new_project();
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
add_recent_project(project_url);
|
||||
}
|
||||
|
||||
void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int type) {
|
||||
@@ -970,5 +795,47 @@ void Project::save_project() {
|
||||
|
||||
file.close();
|
||||
|
||||
add_recent_project(project_url);
|
||||
|
||||
project_changed = false;
|
||||
}
|
||||
|
||||
void Project::save_recent_projects() {
|
||||
// save to file
|
||||
QFile f(recent_proj_file);
|
||||
if (f.open(QFile::WriteOnly | QFile::Truncate | QFile::Text)) {
|
||||
QTextStream out(&f);
|
||||
for (int i=0;i<recent_projects.size();i++) {
|
||||
if (i > 0) {
|
||||
out << "\n";
|
||||
}
|
||||
out << recent_projects.at(i);
|
||||
}
|
||||
f.close();
|
||||
} else {
|
||||
qDebug() << "[WARNING] Could not save recent projects";
|
||||
}
|
||||
}
|
||||
|
||||
void Project::clear_recent_projects() {
|
||||
recent_projects.clear();
|
||||
save_recent_projects();
|
||||
}
|
||||
|
||||
void Project::add_recent_project(QString url) {
|
||||
bool found = false;
|
||||
for (int i=0;i<recent_projects.size();i++) {
|
||||
if (url == recent_projects.at(i)) {
|
||||
found = true;
|
||||
recent_projects.move(i, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
recent_projects.insert(0, url);
|
||||
if (recent_projects.size() > MAXIMUM_RECENT_PROJECTS) {
|
||||
recent_projects.removeLast();
|
||||
}
|
||||
}
|
||||
save_recent_projects();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class Project;
|
||||
|
||||
extern bool project_changed;
|
||||
extern QString project_url;
|
||||
extern QStringList recent_projects;
|
||||
extern QString recent_proj_file;
|
||||
|
||||
class Project : public QDockWidget
|
||||
{
|
||||
@@ -73,8 +75,11 @@ private:
|
||||
QVector<QTreeWidgetItem*> loaded_folders;
|
||||
QVector<Media*> loaded_media;
|
||||
QTreeWidgetItem* find_loaded_folder_by_id(int id);
|
||||
void add_recent_project(QString url);
|
||||
void save_recent_projects();
|
||||
private slots:
|
||||
void rename_media(QTreeWidgetItem* item, int column);
|
||||
void clear_recent_projects();
|
||||
};
|
||||
|
||||
#endif // PROJECT_H
|
||||
|
||||
@@ -267,4 +267,5 @@ void set_sequence(Sequence* s) {
|
||||
sequence = s;
|
||||
panel_timeline->update_sequence();
|
||||
panel_viewer->update_sequence();
|
||||
panel_timeline->setFocus();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ void SourceTable::mousePressEvent(QMouseEvent* event) {
|
||||
}
|
||||
|
||||
void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) {
|
||||
stop_rename_timer();
|
||||
if (selectedItems().count() == 0) {
|
||||
panel_project->import_dialog();
|
||||
} else if (selectedItems().count() == 1) {
|
||||
|
||||
@@ -985,7 +985,6 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
for (int i=0;i<track_size;i++) {
|
||||
int clip_index = getClipIndexFromCoords(panel_timeline->drag_frame_start, panel_timeline->split_tracks[i]);
|
||||
if (clip_index > -1) {
|
||||
Clip* c = sequence->get_clip(clip_index);
|
||||
QVector<int> tracks = panel_timeline->get_tracks_of_linked_clips(clip_index);
|
||||
for (int j=0;j<tracks.size();j++) {
|
||||
// check if this track is already included
|
||||
|
||||
Reference in New Issue
Block a user