Subversion Repositories svn.mios32

Rev

Rev 1724 | Rev 1734 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1724 Rev 1726
1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MiosFileBrowser.cpp 1724 2013-03-28 20:23:40Z tk $
2
// $Id: MiosFileBrowser.cpp 1726 2013-03-28 21:20:34Z tk $
3
/*
3
/*
4
 * File browser for MIOS32 applications
4
 * File browser for MIOS32 applications
5
 *
5
 *
6
 * ==========================================================================
6
 * ==========================================================================
7
 *
7
 *
8
 *  Copyright (C) 2012 Thorsten Klose (tk@midibox.org)
8
 *  Copyright (C) 2012 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
10
 *  All other rights reserved.
11
 *
11
 *
12
 * ==========================================================================
12
 * ==========================================================================
13
 */
13
 */
14
14
15
#include "MiosFileBrowser.h"
15
#include "MiosFileBrowser.h"
16
#include "MiosStudio.h"
16
#include "MiosStudio.h"
17
17
18
//==============================================================================
18
//==============================================================================
19
class MiosFileBrowserFileItem
19
class MiosFileBrowserFileItem
20
{
20
{
21
public:
21
public:
22
    String parentPath;
22
    String parentPath;
23
    String name;
23
    String name;
24
    bool isDirectory;
24
    bool isDirectory;
25
25
26
    OwnedArray<MiosFileBrowserFileItem> childs;
26
    OwnedArray<MiosFileBrowserFileItem> childs;
27
27
28
    MiosFileBrowserFileItem(String _parentPath, String _itemName, bool _isDirectory)
28
    MiosFileBrowserFileItem(String _parentPath, String _itemName, bool _isDirectory)
29
        : parentPath(_parentPath)
29
        : parentPath(_parentPath)
30
        , name(_itemName)
30
        , name(_itemName)
31
        , isDirectory(_isDirectory)
31
        , isDirectory(_isDirectory)
32
    {
32
    {
33
    }
33
    }
34
34
35
    ~MiosFileBrowserFileItem()
35
    ~MiosFileBrowserFileItem()
36
    {
36
    {
37
    }
37
    }
38
38
39
    MiosFileBrowserFileItem* createChild(String parentPath, String childName, bool isDirectory) {
39
    MiosFileBrowserFileItem* createChild(String parentPath, String childName, bool isDirectory) {
40
        MiosFileBrowserFileItem* child = new MiosFileBrowserFileItem(parentPath, childName, isDirectory);
40
        MiosFileBrowserFileItem* child = new MiosFileBrowserFileItem(parentPath, childName, isDirectory);
41
        childs.add(child);
41
        childs.add(child);
42
        return child;
42
        return child;
43
    }
43
    }
44
};
44
};
45
45
46
46
47
//==============================================================================
47
//==============================================================================
48
class MiosFileBrowserItem : public TreeViewItem
48
class MiosFileBrowserItem : public TreeViewItem
49
{
49
{
50
public:
50
public:
51
    MiosFileBrowserFileItem *fileItem;
51
    MiosFileBrowserFileItem *fileItem;
52
    MiosFileBrowser* browser;
52
    MiosFileBrowser* browser;
53
53
54
    MiosFileBrowserItem(MiosFileBrowserFileItem *_fileItem, MiosFileBrowser* _browser)
54
    MiosFileBrowserItem(MiosFileBrowserFileItem *_fileItem, MiosFileBrowser* _browser)
55
        : fileItem(_fileItem)
55
        : fileItem(_fileItem)
56
        , browser(_browser)
56
        , browser(_browser)
57
    {
57
    {
58
    }
58
    }
59
59
60
    ~MiosFileBrowserItem()
60
    ~MiosFileBrowserItem()
61
    {
61
    {
62
    }
62
    }
63
63
64
    int getItemWidth() const
64
    int getItemWidth() const
65
    {
65
    {
66
        return 100;
66
        return 100;
67
    }
67
    }
68
68
69
    String getUniqueName() const
69
    String getUniqueName() const
70
    {
70
    {
71
        if( fileItem->parentPath.compare(T("/")) == 0 ) {
71
        if( fileItem->parentPath.compare(T("/")) == 0 ) {
72
            return T("/") + fileItem->name;
72
            return T("/") + fileItem->name;
73
        } else {
73
        } else {
74
            if( fileItem->name.compare(T("/")) == 0 )
74
            if( fileItem->name.compare(T("/")) == 0 )
75
                return T("/");
75
                return T("/");
76
            else
76
            else
77
                return fileItem->parentPath + T("/") + fileItem->name;
77
                return fileItem->parentPath + T("/") + fileItem->name;
78
        }
78
        }
79
    }
79
    }
80
80
81
    bool mightContainSubItems()
81
    bool mightContainSubItems()
82
    {
82
    {
83
        return fileItem->isDirectory;
83
        return fileItem->isDirectory;
84
    }
84
    }
85
85
86
    void paintItem (Graphics& g, int width, int height)
86
    void paintItem (Graphics& g, int width, int height)
87
    {
87
    {
88
        // if this item is selected, fill it with a background colour..
88
        // if this item is selected, fill it with a background colour..
89
        if( isSelected() )
89
        if( isSelected() )
90
            g.fillAll(Colours::blue.withAlpha (0.3f));
90
            g.fillAll(Colours::blue.withAlpha (0.3f));
91
91
92
        // use a "colour" attribute in the xml tag for this node to set the text colour..
92
        // use a "colour" attribute in the xml tag for this node to set the text colour..
93
        g.setColour(Colour(0xff000000));
93
        g.setColour(Colour(0xff000000));
94
94
95
        g.setFont(height * 0.7f);
95
        g.setFont(height * 0.7f);
96
96
97
        // draw the item name
97
        // draw the item name
98
        String name(fileItem->name);
98
        String name(fileItem->name);
99
        g.drawText(name,
99
        g.drawText(name,
100
                   4, 0, width - 4, height,
100
                   4, 0, width - 4, height,
101
                   Justification::centredLeft, true);
101
                   Justification::centredLeft, true);
102
    }
102
    }
103
103
104
    void itemOpennessChanged (bool isNowOpen)
104
    void itemOpennessChanged (bool isNowOpen)
105
    {
105
    {
106
        if( isNowOpen ) {
106
        if( isNowOpen ) {
107
            // if we've not already done so, we'll now add the tree's sub-items. You could
107
            // if we've not already done so, we'll now add the tree's sub-items. You could
108
            // also choose to delete the existing ones and refresh them if that's more suitable
108
            // also choose to delete the existing ones and refresh them if that's more suitable
109
            // in your app.
109
            // in your app.
110
            if( getNumSubItems() == 0 ) {
110
            if( getNumSubItems() == 0 ) {
111
                for(int i=0; i<fileItem->childs.size(); ++i) {
111
                for(int i=0; i<fileItem->childs.size(); ++i) {
112
                    MiosFileBrowserItem* item;
112
                    MiosFileBrowserItem* item;
113
                    addSubItem(item = new MiosFileBrowserItem(fileItem->childs[i], browser));
113
                    addSubItem(item = new MiosFileBrowserItem(fileItem->childs[i], browser));
114
                }
114
                }
115
            }
115
            }
116
        } else {
116
        } else {
117
            // in this case, we'll leave any sub-items in the tree when the node gets closed,
117
            // in this case, we'll leave any sub-items in the tree when the node gets closed,
118
            // though you could choose to delete them if that's more appropriate for
118
            // though you could choose to delete them if that's more appropriate for
119
            // your application.
119
            // your application.
120
        }
120
        }
121
    }
121
    }
122
122
123
123
124
    void itemClicked (const MouseEvent& e)
124
    void itemClicked (const MouseEvent& e)
125
    {
125
    {
126
        if( getOwnerView()->isEnabled() )
126
        if( getOwnerView()->isEnabled() )
127
            browser->treeItemClicked(this);
127
            browser->treeItemClicked(this);
128
    }
128
    }
129
129
130
    void itemDoubleClicked (const MouseEvent& e)
130
    void itemDoubleClicked (const MouseEvent& e)
131
    {
131
    {
132
        TreeViewItem::itemDoubleClicked(e);
132
        TreeViewItem::itemDoubleClicked(e);
133
        if( getOwnerView()->isEnabled() )
133
        if( getOwnerView()->isEnabled() )
134
            browser->treeItemDoubleClicked(this);
134
            browser->treeItemDoubleClicked(this);
135
    }
135
    }
136
136
137
    var getDragSourceDescription()
137
    var getDragSourceDescription()
138
    {
138
    {
139
        return "MIOS Filebrowser Items";
139
        return "MIOS Filebrowser Items";
140
    }
140
    }
141
141
142
private:
142
private:
143
};
143
};
144
144
145
//==============================================================================
145
//==============================================================================
146
//==============================================================================
146
//==============================================================================
147
//==============================================================================
147
//==============================================================================
148
MiosFileBrowser::MiosFileBrowser(MiosStudio *_miosStudio)
148
MiosFileBrowser::MiosFileBrowser(MiosStudio *_miosStudio)
149
    : miosStudio(_miosStudio)
149
    : miosStudio(_miosStudio)
150
    , rootItem(NULL)
150
    , rootItem(NULL)
151
    , rootFileItem(NULL)
151
    , rootFileItem(NULL)
152
    , currentDirOpenStates(NULL)
152
    , currentDirOpenStates(NULL)
153
    , transferSelectionCtr(0)
153
    , transferSelectionCtr(0)
154
    , openTextEditorAfterRead(false)
154
    , openTextEditorAfterRead(false)
155
    , openHexEditorAfterRead(false)
155
    , openHexEditorAfterRead(false)
156
    , currentReadInProgress(false)
156
    , currentReadInProgress(false)
157
    , currentReadFileBrowserItem(NULL)
157
    , currentReadFileBrowserItem(NULL)
158
    , currentReadFileStream(NULL)
158
    , currentReadFileStream(NULL)
159
    , currentReadError(false)
159
    , currentReadError(false)
160
    , currentWriteInProgress(false)
160
    , currentWriteInProgress(false)
161
    , currentWriteError(false)
161
    , currentWriteError(false)
162
    , writeBlockCtrDefault(32) // send 32 blocks (=two 512 byte SD Card Sectors) at once to speed-up write operations
162
    , writeBlockCtrDefault(32) // send 32 blocks (=two 512 byte SD Card Sectors) at once to speed-up write operations
163
    , writeBlockSizeDefault(32) // send 32 bytes per block
163
    , writeBlockSizeDefault(32) // send 32 bytes per block
164
{
164
{
165
    addAndMakeVisible(editLabel = new Label(T("Edit"), String::empty));
165
    addAndMakeVisible(editLabel = new Label(T("Edit"), String::empty));
166
    editLabel->setJustificationType(Justification::left);
166
    editLabel->setJustificationType(Justification::left);
167
    editLabel->setText(String::empty, true);
167
    editLabel->setText(String::empty, true);
168
168
169
    addAndMakeVisible(statusLabel = new Label(T("Status"), String::empty));
169
    addAndMakeVisible(statusLabel = new Label(T("Status"), String::empty));
170
    statusLabel->setJustificationType(Justification::left);
170
    statusLabel->setJustificationType(Justification::left);
171
    statusLabel->setText(T("Please connect to MIOS32 core by pressing the Update button!"), true);
171
    statusLabel->setText(T("Please connect to MIOS32 core by pressing the Update button!"), true);
172
172
173
    addAndMakeVisible(updateButton = new TextButton(T("Update")));
173
    addAndMakeVisible(updateButton = new TextButton(T("Update")));
174
    updateButton->addListener(this);
174
    updateButton->addListener(this);
175
175
176
    addAndMakeVisible(uploadButton = new TextButton(T("Upload")));
176
    addAndMakeVisible(uploadButton = new TextButton(T("Upload")));
177
    uploadButton->addListener(this);
177
    uploadButton->addListener(this);
178
178
179
    addAndMakeVisible(downloadButton = new TextButton(T("Download")));
179
    addAndMakeVisible(downloadButton = new TextButton(T("Download")));
180
    downloadButton->addListener(this);
180
    downloadButton->addListener(this);
181
181
182
    addAndMakeVisible(editTextButton = new TextButton(T("Edit Text")));
182
    addAndMakeVisible(editTextButton = new TextButton(T("Edit Text")));
183
    editTextButton->addListener(this);
183
    editTextButton->addListener(this);
184
184
185
    addAndMakeVisible(editHexButton = new TextButton(T("Edit Hex")));
185
    addAndMakeVisible(editHexButton = new TextButton(T("Edit Hex")));
186
    editHexButton->addListener(this);
186
    editHexButton->addListener(this);
187
187
188
    addAndMakeVisible(createDirButton = new TextButton(T("Create Dir")));
188
    addAndMakeVisible(createDirButton = new TextButton(T("Create Dir")));
189
    createDirButton->addListener(this);
189
    createDirButton->addListener(this);
190
190
191
    addAndMakeVisible(createFileButton = new TextButton(T("Create File")));
191
    addAndMakeVisible(createFileButton = new TextButton(T("Create File")));
192
    createFileButton->addListener(this);
192
    createFileButton->addListener(this);
193
193
194
    addAndMakeVisible(removeButton = new TextButton(T("Remove Button")));
194
    addAndMakeVisible(removeButton = new TextButton(T("Remove Button")));
195
    removeButton->setButtonText(T("Remove"));
195
    removeButton->setButtonText(T("Remove"));
196
    removeButton->addListener(this);
196
    removeButton->addListener(this);
197
197
198
    addAndMakeVisible(cancelButton = new TextButton(T("Cancel")));
198
    addAndMakeVisible(cancelButton = new TextButton(T("Cancel")));
199
    cancelButton->addListener(this);
199
    cancelButton->addListener(this);
200
    cancelButton->setEnabled(false);
200
    cancelButton->setEnabled(false);
201
201
202
    addAndMakeVisible(saveButton = new TextButton(T("Save")));
202
    addAndMakeVisible(saveButton = new TextButton(T("Save")));
203
    saveButton->addListener(this);
203
    saveButton->addListener(this);
204
    saveButton->setEnabled(false);
204
    saveButton->setEnabled(false);
205
205
206
    addAndMakeVisible(treeView = new TreeView(T("SD Card")));
206
    addAndMakeVisible(treeView = new TreeView(T("SD Card")));
207
    treeView->setMultiSelectEnabled(true);
207
    treeView->setMultiSelectEnabled(true);
208
208
209
    addAndMakeVisible(hexEditor = new HexTextEditor(statusLabel));
209
    addAndMakeVisible(hexEditor = new HexTextEditor(statusLabel));
210
    hexEditor->setReadOnly(true);
210
    hexEditor->setReadOnly(true);
211
211
212
    addAndMakeVisible(textEditor = new TextEditor(String::empty));
212
    addAndMakeVisible(textEditor = new TextEditor(String::empty));
213
    textEditor->setMultiLine(true);
213
    textEditor->setMultiLine(true);
214
    textEditor->setReturnKeyStartsNewLine(true);
214
    textEditor->setReturnKeyStartsNewLine(true);
215
    textEditor->setReadOnly(false);
215
    textEditor->setReadOnly(false);
216
    textEditor->setScrollbarsShown(true);
216
    textEditor->setScrollbarsShown(true);
217
    textEditor->setCaretVisible(true);
217
    textEditor->setCaretVisible(true);
218
    textEditor->setPopupMenuEnabled(true);
218
    textEditor->setPopupMenuEnabled(true);
219
    textEditor->setReadOnly(true);
219
    textEditor->setReadOnly(true);
220
    textEditor->setVisible(false); // either hex or text editor visible
220
    textEditor->setVisible(false); // either hex or text editor visible
221
#if JUCE_MAJOR_VERSION==1 && JUCE_MINOR_VERSION<51
221
#if JUCE_MAJOR_VERSION==1 && JUCE_MINOR_VERSION<51
222
#if defined(JUCE_WIN32)
222
#if defined(JUCE_WIN32)
223
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 10.0, 0));
223
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 10.0, 0));
224
#else
224
#else
225
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 13.0, 0));
225
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 13.0, 0));
226
#endif
226
#endif
227
#else
227
#else
228
#if defined(JUCE_WIN32)
228
#if defined(JUCE_WIN32)
229
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 10.0, 0));
229
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 10.0, 0));
230
#else
230
#else
231
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 13.0, 0));
231
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 13.0, 0));
232
#endif
232
#endif
233
#endif
233
#endif
234
    textEditor->addListener(this);
234
    textEditor->addListener(this);
235
235
236
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
236
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
237
    currentDirItem = rootFileItem;
237
    currentDirItem = rootFileItem;
238
    updateTreeView(false);
238
    updateTreeView(false);
239
239
240
    resizeLimits.setSizeLimits(500, 320, 2048, 2048);
240
    resizeLimits.setSizeLimits(500, 320, 2048, 2048);
241
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
241
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
242
242
243
    setSize(950, 500);
243
    setSize(950, 500);
244
}
244
}
245
245
246
MiosFileBrowser::~MiosFileBrowser()
246
MiosFileBrowser::~MiosFileBrowser()
247
{
247
{
248
}
248
}
249
249
250
//==============================================================================
250
//==============================================================================
251
void MiosFileBrowser::paint (Graphics& g)
251
void MiosFileBrowser::paint (Graphics& g)
252
{
252
{
253
    //g.fillAll(Colour(0xffc1d0ff));
253
    //g.fillAll(Colour(0xffc1d0ff));
254
    g.fillAll(Colour(0xffffffff));
254
    g.fillAll(Colour(0xffffffff));
255
}
255
}
256
256
257
void MiosFileBrowser::resized()
257
void MiosFileBrowser::resized()
258
{
258
{
259
    int sendButtonY = 16;
259
    int sendButtonY = 16;
260
    int sendButtonWidth = 72;
260
    int sendButtonWidth = 72;
261
 
261
 
262
    updateButton->setBounds    (10 , sendButtonY + 0*32 + 0*16, sendButtonWidth, 24);
262
    updateButton->setBounds    (10 , sendButtonY + 0*32 + 0*16, sendButtonWidth, 24);
263
    downloadButton->setBounds  (10 , sendButtonY + 1*32 + 1*16, sendButtonWidth, 24);
263
    downloadButton->setBounds  (10 , sendButtonY + 1*32 + 1*16, sendButtonWidth, 24);
264
    uploadButton->setBounds    (10 , sendButtonY + 2*32 + 1*16, sendButtonWidth, 24);
264
    uploadButton->setBounds    (10 , sendButtonY + 2*32 + 1*16, sendButtonWidth, 24);
265
    createDirButton->setBounds (10 , sendButtonY + 3*32 + 3*16, sendButtonWidth, 24);
265
    createDirButton->setBounds (10 , sendButtonY + 3*32 + 3*16, sendButtonWidth, 24);
266
    createFileButton->setBounds(10 , sendButtonY + 4*32 + 3*16, sendButtonWidth, 24);
266
    createFileButton->setBounds(10 , sendButtonY + 4*32 + 3*16, sendButtonWidth, 24);
267
    removeButton->setBounds    (10 , sendButtonY + 5*32 + 4*16, sendButtonWidth, 24);
267
    removeButton->setBounds    (10 , sendButtonY + 5*32 + 4*16, sendButtonWidth, 24);
268
268
269
    treeView->setBounds        (10 + 80, 16, 210, getHeight()-32-24);
269
    treeView->setBounds        (10 + 80, 16, 210, getHeight()-32-24);
270
270
271
    hexEditor->setBounds       (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
271
    hexEditor->setBounds       (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
272
    textEditor->setBounds      (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
272
    textEditor->setBounds      (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
273
273
274
    editTextButton->setBounds  (10+80+220 + 0*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
274
    editTextButton->setBounds  (10+80+220 + 0*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
275
    editHexButton->setBounds   (10+80+220 + 1*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
275
    editHexButton->setBounds   (10+80+220 + 1*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
276
    cancelButton->setBounds    (getWidth()-10-sendButtonWidth, sendButtonY, sendButtonWidth, 24);
276
    cancelButton->setBounds    (getWidth()-10-sendButtonWidth, sendButtonY, sendButtonWidth, 24);
277
    saveButton->setBounds      (getWidth()-10-2*sendButtonWidth-10, sendButtonY, sendButtonWidth, 24);
277
    saveButton->setBounds      (getWidth()-10-2*sendButtonWidth-10, sendButtonY, sendButtonWidth, 24);
278
278
279
    unsigned editLabelLeft  = editHexButton->getX()+editHexButton->getWidth() + 10;
279
    unsigned editLabelLeft  = editHexButton->getX()+editHexButton->getWidth() + 10;
280
    unsigned editLabelRight = saveButton->getX() - 10;
280
    unsigned editLabelRight = saveButton->getX() - 10;
281
    editLabel->setBounds       (editLabelLeft, sendButtonY, editLabelRight-editLabelLeft, 24);
281
    editLabel->setBounds       (editLabelLeft, sendButtonY, editLabelRight-editLabelLeft, 24);
282
282
283
    statusLabel->setBounds(10, getHeight()-24, getWidth()-20, 24);
283
    statusLabel->setBounds(10, getHeight()-24, getWidth()-20, 24);
284
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
284
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
285
}
285
}
286
286
287
//==============================================================================
287
//==============================================================================
288
void MiosFileBrowser::buttonClicked(Button* buttonThatWasClicked)
288
void MiosFileBrowser::buttonClicked(Button* buttonThatWasClicked)
289
{
289
{
290
    if( buttonThatWasClicked == updateButton ) {
290
    if( buttonThatWasClicked == updateButton ) {
291
        // ensure that we see the first position of the treeview
291
        // ensure that we see the first position of the treeview
292
        treeView->clearSelectedItems();
292
        treeView->clearSelectedItems();
293
        treeView->scrollToKeepItemVisible(rootItem);
293
        treeView->scrollToKeepItemVisible(rootItem);
294
        // change label
294
        // change label
295
        statusLabel->setText(T(""), true);
295
        statusLabel->setText(T(""), true);
296
        // request update
296
        // request update
297
        requestUpdateTreeView();
297
        requestUpdateTreeView();
298
    } else if( buttonThatWasClicked == downloadButton ||
298
    } else if( buttonThatWasClicked == downloadButton ||
299
               buttonThatWasClicked == editTextButton ||
299
               buttonThatWasClicked == editTextButton ||
300
               buttonThatWasClicked == editHexButton ) {
300
               buttonThatWasClicked == editHexButton ) {
301
301
302
        // extra: if data is edited, switch between hex/text view
302
        // extra: if data is edited, switch between hex/text view
303
        if( saveButton->isEnabled() ) {
303
        if( saveButton->isEnabled() ) {
304
            // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
304
            // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
305
            if( currentReadFileBrowserItem ) {
305
            if( currentReadFileBrowserItem ) {
306
                currentReadFileBrowserItem->setSelected(true, true);
306
                currentReadFileBrowserItem->setSelected(true, true);
307
                treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
307
                treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
308
            }
308
            }
309
309
310
            if( buttonThatWasClicked == editTextButton && hexEditor->isVisible() ) {
310
            if( buttonThatWasClicked == editTextButton && hexEditor->isVisible() ) {
311
                openTextEditor(hexEditor->getBinary());
311
                openTextEditor(hexEditor->getBinary());
312
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in text mode."), true);
312
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in text mode."), true);
313
            } else if( buttonThatWasClicked == editHexButton && textEditor->isVisible() ) {
313
            } else if( buttonThatWasClicked == editHexButton && textEditor->isVisible() ) {
314
                if( textEditor->isVisible() && !textEditor->isReadOnly() ) {
314
                if( textEditor->isVisible() && !textEditor->isReadOnly() ) {
315
                    // visible & read only mode means, that binary data is edited -> transfer to Hex Editor only in this case!
315
                    // visible & read only mode means, that binary data is edited -> transfer to Hex Editor only in this case!
316
                    String tmpStr(textEditor->getText());
316
                    String tmpStr(textEditor->getText());
317
                    Array<uint8> data((uint8 *)tmpStr.toUTF8().getAddress(), tmpStr.length());
317
                    Array<uint8> data((uint8 *)tmpStr.toUTF8().getAddress(), tmpStr.length());
318
                    openHexEditor(data);
318
                    openHexEditor(data);
319
                } else {
319
                } else {
320
                    // otherwise re-use data in hex editor
320
                    // otherwise re-use data in hex editor
321
                    openHexEditor(hexEditor->getBinary());
321
                    openHexEditor(hexEditor->getBinary());
322
                }
322
                }
323
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in hex mode."), true);
323
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in hex mode."), true);
324
            }
324
            }
325
        } else {
325
        } else {
326
            if( treeView->getNumSelectedItems() ) {
326
            if( treeView->getNumSelectedItems() ) {
327
                openTextEditorAfterRead = buttonThatWasClicked == editTextButton;
327
                openTextEditorAfterRead = buttonThatWasClicked == editTextButton;
328
                openHexEditorAfterRead = buttonThatWasClicked == editHexButton;
328
                openHexEditorAfterRead = buttonThatWasClicked == editHexButton;
329
                transferSelectionCtr = 0;
329
                transferSelectionCtr = 0;
330
                downloadFileSelection(transferSelectionCtr);
330
                downloadFileSelection(transferSelectionCtr);
331
            }
331
            }
332
        }
332
        }
333
    } else if( buttonThatWasClicked == uploadButton ) {
333
    } else if( buttonThatWasClicked == uploadButton ) {
334
        uploadFile();
334
        uploadFile();
335
    } else if( buttonThatWasClicked == createDirButton ) {
335
    } else if( buttonThatWasClicked == createDirButton ) {
336
        createDir();
336
        createDir();
337
    } else if( buttonThatWasClicked == createFileButton ) {
337
    } else if( buttonThatWasClicked == createFileButton ) {
338
        createFile();
338
        createFile();
339
    } else if( buttonThatWasClicked == removeButton ) {
339
    } else if( buttonThatWasClicked == removeButton ) {
340
        if( treeView->getNumSelectedItems() ) {
340
        if( treeView->getNumSelectedItems() ) {
341
            transferSelectionCtr = 0;
341
            transferSelectionCtr = 0;
342
            deleteFileSelection(transferSelectionCtr);
342
            deleteFileSelection(transferSelectionCtr);
343
        }
343
        }
344
    } else if( buttonThatWasClicked == cancelButton ||
344
    } else if( buttonThatWasClicked == cancelButton ||
345
               buttonThatWasClicked == saveButton ) {
345
               buttonThatWasClicked == saveButton ) {
346
346
347
        if( buttonThatWasClicked == cancelButton ) {
347
        if( buttonThatWasClicked == cancelButton ) {
348
            openHexEditorAfterRead = false;
348
            openHexEditorAfterRead = false;
349
            openTextEditorAfterRead = false;
349
            openTextEditorAfterRead = false;
350
            enableFileButtons();
350
            enableFileButtons();
351
            hexEditor->clear();
351
            hexEditor->clear();
352
            hexEditor->setReadOnly(true);
352
            hexEditor->setReadOnly(true);
353
            textEditor->clear();
353
            textEditor->clear();
354
            textEditor->setReadOnly(true);
354
            textEditor->setReadOnly(true);
355
            editLabel->setText(String::empty, true);
355
            editLabel->setText(String::empty, true);
356
356
357
            disableFileButtons(); // to disable also editor buttons
357
            disableFileButtons(); // to disable also editor buttons
358
            enableFileButtons();
358
            enableFileButtons();
359
        } else if( buttonThatWasClicked == saveButton ) {
359
        } else if( buttonThatWasClicked == saveButton ) {
360
            if( hexEditor->isVisible() ) {
360
            if( hexEditor->isVisible() ) {
361
                // write back the read file
361
                // write back the read file
362
                uploadBuffer(currentReadFileName, hexEditor->getBinary());
362
                uploadBuffer(currentReadFileName, hexEditor->getBinary());
363
            } else if( textEditor->isVisible() ) {
363
            } else if( textEditor->isVisible() ) {
364
                // write back the read file
364
                // write back the read file
365
                String txt(textEditor->getText());
365
                String txt(textEditor->getText());
366
                Array<uint8> tmp((uint8 *)txt.toUTF8().getAddress(), txt.length());
366
                Array<uint8> tmp((uint8 *)txt.toUTF8().getAddress(), txt.length());
367
                uploadBuffer(currentReadFileName, tmp);
367
                uploadBuffer(currentReadFileName, tmp);
368
            }
368
            }
369
        }
369
        }
370
    }
370
    }
371
}
371
}
372
372
373
373
374
//==============================================================================
374
//==============================================================================
375
void MiosFileBrowser::textEditorTextChanged(TextEditor &editor)
375
void MiosFileBrowser::textEditorTextChanged(TextEditor &editor)
376
{
376
{
377
    // unfortunately not updated on any cursor move...
377
    // unfortunately not updated on any cursor move...
378
#if 0
378
#if 0
379
    int pos = editor.getCaretPosition();
379
    int pos = editor.getCaretPosition();
380
    String txt(editor.getText());
380
    String txt(editor.getText());
381
    statusLabel->setText(String::formatted(T("(%d/%d)"), pos, txt.length()), true);
381
    statusLabel->setText(String::formatted(T("(%d/%d)"), pos, txt.length()), true);
382
#endif
382
#endif
383
}
383
}
384
384
385
void MiosFileBrowser::textEditorReturnKeyPressed(TextEditor &editor)
385
void MiosFileBrowser::textEditorReturnKeyPressed(TextEditor &editor)
386
{
386
{
387
}
387
}
388
388
389
void MiosFileBrowser::textEditorEscapeKeyPressed(TextEditor &editor)
389
void MiosFileBrowser::textEditorEscapeKeyPressed(TextEditor &editor)
390
{
390
{
391
}
391
}
392
392
393
void MiosFileBrowser::textEditorFocusLost(TextEditor &editor)
393
void MiosFileBrowser::textEditorFocusLost(TextEditor &editor)
394
{
394
{
395
}
395
}
396
396
397
397
398
//==============================================================================
398
//==============================================================================
399
String MiosFileBrowser::getSelectedPath(void)
399
String MiosFileBrowser::getSelectedPath(void)
400
{
400
{
401
    String selectedPath(T("/"));
401
    String selectedPath(T("/"));
402
402
403
    TreeViewItem* selectedItem = treeView->getSelectedItem(0);
403
    TreeViewItem* selectedItem = treeView->getSelectedItem(0);
404
    if( selectedItem ) {
404
    if( selectedItem ) {
405
        selectedPath = selectedItem->getUniqueName();
405
        selectedPath = selectedItem->getUniqueName();
406
        if( selectedPath.compare(T("/")) != 0 ) {
406
        if( selectedPath.compare(T("/")) != 0 ) {
407
            if( !selectedItem->mightContainSubItems() ) {
407
            if( !selectedItem->mightContainSubItems() ) {
408
                selectedPath = selectedPath.substring(0, selectedPath.lastIndexOfChar('/')) + T("/");
408
                selectedPath = selectedPath.substring(0, selectedPath.lastIndexOfChar('/')) + T("/");
409
            } else {
409
            } else {
410
                selectedPath += T("/");
410
                selectedPath += T("/");
411
            }
411
            }
412
        }
412
        }
413
    }
413
    }
414
414
415
    //std::cout << "Selected Path: " << selectedPath << std::endl;
415
    //std::cout << "Selected Path: " << selectedPath << std::endl;
416
416
417
    return selectedPath;
417
    return selectedPath;
418
}
418
}
419
419
420
//==============================================================================
420
//==============================================================================
421
void MiosFileBrowser::disableFileButtons(void)
421
void MiosFileBrowser::disableFileButtons(void)
422
{
422
{
423
    updateButton->setEnabled(true);
423
    updateButton->setEnabled(true);
424
    uploadButton->setEnabled(false);
424
    uploadButton->setEnabled(false);
425
    downloadButton->setEnabled(false);
425
    downloadButton->setEnabled(false);
426
    createDirButton->setEnabled(false);
426
    createDirButton->setEnabled(false);
427
    createFileButton->setEnabled(false);
427
    createFileButton->setEnabled(false);
428
    removeButton->setEnabled(false);
428
    removeButton->setEnabled(false);
429
429
430
    // important: don't disable save/cancel button as long as an open editor has content
430
    // important: don't disable save/cancel button as long as an open editor has content
431
    // (in case of write error)
431
    // (in case of write error)
432
    if( !(textEditor->isVisible() && textEditor->getText().length()) &&
432
    if( !(textEditor->isVisible() && textEditor->getText().length()) &&
433
        !(hexEditor->isVisible() && hexEditor->getBinary().size()) ) {
433
        !(hexEditor->isVisible() && hexEditor->getBinary().size()) ) {
434
        editTextButton->setEnabled(false);
434
        editTextButton->setEnabled(false);
435
        editHexButton->setEnabled(false);
435
        editHexButton->setEnabled(false);
436
        hexEditor->setReadOnly(true);
436
        hexEditor->setReadOnly(true);
437
        textEditor->setReadOnly(true);
437
        textEditor->setReadOnly(true);
438
        saveButton->setEnabled(false);
438
        saveButton->setEnabled(false);
439
        cancelButton->setEnabled(false);
439
        cancelButton->setEnabled(false);
440
    }
440
    }
441
}
441
}
442
442
443
void MiosFileBrowser::enableFileButtons(void)
443
void MiosFileBrowser::enableFileButtons(void)
444
{
444
{
445
    treeView->setEnabled(true);
445
    treeView->setEnabled(true);
446
446
447
    updateButton->setEnabled(true);
447
    updateButton->setEnabled(true);
448
    uploadButton->setEnabled(true);
448
    uploadButton->setEnabled(true);
449
    downloadButton->setEnabled(true);
449
    downloadButton->setEnabled(true);
450
    editTextButton->setEnabled(true);
450
    editTextButton->setEnabled(true);
451
    editHexButton->setEnabled(true);
451
    editHexButton->setEnabled(true);
452
    createDirButton->setEnabled(true);
452
    createDirButton->setEnabled(true);
453
    createFileButton->setEnabled(true);
453
    createFileButton->setEnabled(true);
454
    removeButton->setEnabled(true);
454
    removeButton->setEnabled(true);
455
}
455
}
456
456
457
void MiosFileBrowser::enableDirButtons(void)
457
void MiosFileBrowser::enableDirButtons(void)
458
{
458
{
459
    updateButton->setEnabled(true);
459
    updateButton->setEnabled(true);
460
    uploadButton->setEnabled(true);
460
    uploadButton->setEnabled(true);
461
    createDirButton->setEnabled(true);
461
    createDirButton->setEnabled(true);
462
    createFileButton->setEnabled(true); // no error: we want to create a file in the selected directory
462
    createFileButton->setEnabled(true); // no error: we want to create a file in the selected directory
463
    removeButton->setEnabled(true);
463
    removeButton->setEnabled(true);
464
}
464
}
465
465
466
void MiosFileBrowser::enableEditorButtons(void)
466
void MiosFileBrowser::enableEditorButtons(void)
467
{
467
{
468
    treeView->setEnabled(false);
468
    treeView->setEnabled(false);
469
469
470
    updateButton->setEnabled(false);
470
    updateButton->setEnabled(false);
471
    editTextButton->setEnabled(true);
471
    editTextButton->setEnabled(true);
472
    editHexButton->setEnabled(true);
472
    editHexButton->setEnabled(true);
473
    cancelButton->setEnabled(true);
473
    cancelButton->setEnabled(true);
474
    saveButton->setEnabled(true);
474
    saveButton->setEnabled(true);
475
}
475
}
476
476
477
//==============================================================================
477
//==============================================================================
478
String MiosFileBrowser::convertToString(const Array<uint8>& data, bool& hasBinaryData)
478
String MiosFileBrowser::convertToString(const Array<uint8>& data, bool& hasBinaryData)
479
{
479
{
480
    String str;
480
    String str;
481
    hasBinaryData = false;
481
    hasBinaryData = false;
482
   
482
   
483
    uint8 *ptr = (uint8 *)&data.getReference(0);
483
    uint8 *ptr = (uint8 *)&data.getReference(0);
484
    for(int i=0; i<data.size(); ++i, ++ptr) {
484
    for(int i=0; i<data.size(); ++i, ++ptr) {
485
        if( *ptr == 0 ) {
485
        if( *ptr == 0 ) {
486
            hasBinaryData = true; // full conversion to string not possible
486
            hasBinaryData = true; // full conversion to string not possible
487
            str += "\\0"; // show \0 instead
487
            str += "\\0"; // show \0 instead
488
        } else {
488
        } else {
489
            str += (const wchar_t)*ptr;
489
            str += (const wchar_t)*ptr;
490
        }
490
        }
491
    }
491
    }
492
492
493
    return str;
493
    return str;
494
}
494
}
495
495
496
bool MiosFileBrowser::updateEditors(const Array<uint8>& data)
496
bool MiosFileBrowser::updateEditors(const Array<uint8>& data)
497
{
497
{
498
    // transfer data into both editors, make them read-only and invisible
498
    // transfer data into both editors, make them read-only and invisible
499
    hexEditor->setReadOnly(false);
499
    hexEditor->setReadOnly(false);
500
    hexEditor->clear();
500
    hexEditor->clear();
501
    hexEditor->addBinary((uint8 *)&data.getReference(0), data.size());
501
    hexEditor->addBinary((uint8 *)&data.getReference(0), data.size());
502
    hexEditor->setReadOnly(true);
502
    hexEditor->setReadOnly(true);
503
    hexEditor->setVisible(false);
503
    hexEditor->setVisible(false);
504
504
505
    bool hasBinaryData = false;
505
    bool hasBinaryData = false;
506
    String tmpStr(convertToString(data, hasBinaryData));
506
    String tmpStr(convertToString(data, hasBinaryData));
507
    textEditor->setReadOnly(false);
507
    textEditor->setReadOnly(false);
508
    textEditor->clear();
508
    textEditor->clear();
509
    textEditor->setText(tmpStr, true);
509
    textEditor->setText(tmpStr, true);
510
    textEditor->setReadOnly(true);
510
    textEditor->setReadOnly(true);
511
    textEditor->setVisible(false);
511
    textEditor->setVisible(false);
512
512
513
    // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
513
    // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
514
    if( currentReadFileBrowserItem ) {
514
    if( currentReadFileBrowserItem ) {
515
        currentReadFileBrowserItem->setSelected(true, true);
515
        currentReadFileBrowserItem->setSelected(true, true);
516
        treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
516
        treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
517
    }
517
    }
518
518
519
    return hasBinaryData;
519
    return hasBinaryData;
520
}
520
}
521
521
522
void MiosFileBrowser::openTextEditor(const Array<uint8>& data)
522
void MiosFileBrowser::openTextEditor(const Array<uint8>& data)
523
{
523
{
524
    // transfer data to both editors
524
    // transfer data to both editors
525
    bool hasBinaryData = updateEditors(data);
525
    bool hasBinaryData = updateEditors(data);
526
526
527
    disableFileButtons();
527
    disableFileButtons();
528
    enableEditorButtons();
528
    enableEditorButtons();
529
529
530
    // make text editor visible and enable read access if no binary data
530
    // make text editor visible and enable read access if no binary data
531
    textEditor->setVisible(true);
531
    textEditor->setVisible(true);
532
    if( !hasBinaryData ) {
532
    if( !hasBinaryData ) {
533
        textEditor->setReadOnly(false);
533
        textEditor->setReadOnly(false);
534
    } else {
534
    } else {
-
 
535
        // TK: crashes Juce2 - it seems that we are not allowed to use an AlertWindow from the MiosStudio::timerCallback() thread
-
 
536
#if 0
535
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
537
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
536
                                    T("Found binary data!"),
538
                                    T("Found binary data!"),
537
                                    T("This file contains binary data, therefore it\nisn't possible modify it with the text editor!\nPlease use the hex editor instead!"),
539
                                    T("This file contains binary data, therefore it\nisn't possible modify it with the text editor!\nPlease use the hex editor instead!"),
538
                                    T("Ok"));
540
                                    T("Ok"));
-
 
541
#endif
539
    }
542
    }
540
}
543
}
541
544
542
void MiosFileBrowser::openHexEditor(const Array<uint8>& data)
545
void MiosFileBrowser::openHexEditor(const Array<uint8>& data)
543
{
546
{
544
    // transfer data to both editors
547
    // transfer data to both editors
545
    updateEditors(data);
548
    updateEditors(data);
546
549
547
    disableFileButtons();
550
    disableFileButtons();
548
    enableEditorButtons();
551
    enableEditorButtons();
549
552
550
    hexEditor->setVisible(true);
553
    hexEditor->setVisible(true);
551
    hexEditor->setReadOnly(false);
554
    hexEditor->setReadOnly(false);
552
}
555
}
553
556
554
//==============================================================================
557
//==============================================================================
555
void MiosFileBrowser::requestUpdateTreeView(void)
558
void MiosFileBrowser::requestUpdateTreeView(void)
556
{
559
{
557
    treeView->setEnabled(true);
560
    treeView->setEnabled(true);
558
    currentDirOpenStates = treeView->getOpennessState(true); // including scroll position
561
    currentDirOpenStates = treeView->getOpennessState(true); // including scroll position
559
562
560
    if( rootFileItem )
563
    if( rootFileItem )
561
        delete rootFileItem;
564
        delete rootFileItem;
562
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
565
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
563
    currentDirItem = rootFileItem;
566
    currentDirItem = rootFileItem;
564
567
565
    updateTreeView(false);
568
    updateTreeView(false);
566
569
567
    disableFileButtons();
570
    disableFileButtons();
568
    currentDirFetchItems.clear();
571
    currentDirFetchItems.clear();
569
    currentDirPath = T("/");
572
    currentDirPath = T("/");
570
    sendCommand(T("dir ") + currentDirPath);
573
    sendCommand(T("dir ") + currentDirPath);
571
}
574
}
572
575
573
void MiosFileBrowser::updateTreeView(bool accessPossible)
576
void MiosFileBrowser::updateTreeView(bool accessPossible)
574
{
577
{
575
    disableFileButtons();
578
    disableFileButtons();
576
579
577
    if( rootItem )
580
    if( rootItem )
578
        treeView->deleteRootItem();
581
        treeView->deleteRootItem();
579
582
580
    if( rootFileItem ) {
583
    if( rootFileItem ) {
581
        rootItem = new MiosFileBrowserItem(rootFileItem, this);
584
        rootItem = new MiosFileBrowserItem(rootFileItem, this);
582
        rootItem->setOpen(true);
585
        rootItem->setOpen(true);
583
        treeView->setRootItem(rootItem);
586
        treeView->setRootItem(rootItem);
584
587
585
        if( accessPossible ) {
588
        if( accessPossible ) {
586
            if( currentDirOpenStates ) {
589
            if( currentDirOpenStates ) {
587
                treeView->restoreOpennessState(*currentDirOpenStates, true);
590
                treeView->restoreOpennessState(*currentDirOpenStates, true);
588
                deleteAndZero(currentDirOpenStates);
591
                deleteAndZero(currentDirOpenStates);
589
            }
592
            }
590
593
591
            uploadButton->setEnabled(true);
594
            uploadButton->setEnabled(true);
592
            createDirButton->setEnabled(true);
595
            createDirButton->setEnabled(true);
593
            createFileButton->setEnabled(true);
596
            createFileButton->setEnabled(true);
594
        }
597
        }
595
    }
598
    }
596
}
599
}
597
600
598
void MiosFileBrowser::treeItemClicked(MiosFileBrowserItem* item)
601
void MiosFileBrowser::treeItemClicked(MiosFileBrowserItem* item)
599
{
602
{
600
    disableFileButtons();
603
    disableFileButtons();
601
604
602
    if( item->fileItem->isDirectory ) {
605
    if( item->fileItem->isDirectory ) {
603
        enableDirButtons();
606
        enableDirButtons();
604
    } else {
607
    } else {
605
        enableFileButtons();
608
        enableFileButtons();
606
    }
609
    }
607
}
610
}
608
611
609
void MiosFileBrowser::treeItemDoubleClicked(MiosFileBrowserItem* item)
612
void MiosFileBrowser::treeItemDoubleClicked(MiosFileBrowserItem* item)
610
{
613
{
611
}
614
}
612
615
613
//==============================================================================
616
//==============================================================================
614
bool MiosFileBrowser::downloadFileSelection(unsigned selection)
617
bool MiosFileBrowser::downloadFileSelection(unsigned selection)
615
{
618
{
616
    treeView->setEnabled(false);
619
    treeView->setEnabled(false);
617
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
620
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
618
    currentReadFileBrowserItem = selectedItem;
621
    currentReadFileBrowserItem = selectedItem;
619
622
620
    if( selectedItem ) {
623
    if( selectedItem ) {
621
        currentReadFileName = selectedItem->getUniqueName();
624
        currentReadFileName = selectedItem->getUniqueName();
622
625
623
        if( openHexEditorAfterRead || openTextEditorAfterRead ) {
626
        if( openHexEditorAfterRead || openTextEditorAfterRead ) {
624
            disableFileButtons();
627
            disableFileButtons();
625
            sendCommand(T("read ") + currentReadFileName);
628
            sendCommand(T("read ") + currentReadFileName);
626
            return true;
629
            return true;
627
        } else {
630
        } else {
628
            // restore default path
631
            // restore default path
629
            String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
632
            String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
630
            PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
633
            PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
631
            if( propertiesFile ) {
634
            if( propertiesFile ) {
632
                defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
635
                defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
633
            }
636
            }
634
637
635
            String readFileName(currentReadFileName.substring(currentReadFileName.lastIndexOfChar('/')+1));
638
            String readFileName(currentReadFileName.substring(currentReadFileName.lastIndexOfChar('/')+1));
636
            File defaultPathFile(defaultPath + "/" + readFileName);
639
            File defaultPathFile(defaultPath + "/" + readFileName);
637
            FileChooser myChooser(T("Store ") + currentReadFileName, defaultPathFile);
640
            FileChooser myChooser(T("Store ") + currentReadFileName, defaultPathFile);
638
            if( !myChooser.browseForFileToSave(true) ) {
641
            if( !myChooser.browseForFileToSave(true) ) {
639
                statusLabel->setText(T("Cancled save operation for ") + currentReadFileName, true);
642
                statusLabel->setText(T("Cancled save operation for ") + currentReadFileName, true);
640
            } else {
643
            } else {
641
                currentReadFile = myChooser.getResult();
644
                currentReadFile = myChooser.getResult();
642
645
643
                // store default path
646
                // store default path
644
                if( propertiesFile ) {
647
                if( propertiesFile ) {
645
                    propertiesFile->setValue(T("defaultFilebrowserPath"), currentReadFile.getParentDirectory().getFullPathName());
648
                    propertiesFile->setValue(T("defaultFilebrowserPath"), currentReadFile.getParentDirectory().getFullPathName());
646
                }
649
                }
647
650
648
                currentReadFileStream = NULL;
651
                currentReadFileStream = NULL;
649
                currentReadFile.deleteFile();
652
                currentReadFile.deleteFile();
650
                if( !(currentReadFileStream=currentReadFile.createOutputStream()) ||
653
                if( !(currentReadFileStream=currentReadFile.createOutputStream()) ||
651
                    currentReadFileStream->failedToOpen() ) {
654
                    currentReadFileStream->failedToOpen() ) {
652
                    AlertWindow::showMessageBox(AlertWindow::WarningIcon,
655
                    AlertWindow::showMessageBox(AlertWindow::WarningIcon,
653
                                                String::empty,
656
                                                String::empty,
654
                                                T("File cannot be created!"),
657
                                                T("File cannot be created!"),
655
                                                String::empty);
658
                                                String::empty);
656
                    statusLabel->setText(T("Failed to open ") + currentReadFile.getFullPathName(), true);
659
                    statusLabel->setText(T("Failed to open ") + currentReadFile.getFullPathName(), true);
657
                } else {
660
                } else {
658
                    disableFileButtons();
661
                    disableFileButtons();
659
                    sendCommand(T("read ") + currentReadFileName);
662
                    sendCommand(T("read ") + currentReadFileName);
660
                    return true;
663
                    return true;
661
                }
664
                }
662
            }
665
            }
663
        }
666
        }
664
    }
667
    }
665
668
666
    // operation not successfull (or no more files)
669
    // operation not successfull (or no more files)
667
    treeView->setEnabled(true);
670
    treeView->setEnabled(true);
668
    enableFileButtons();
671
    enableFileButtons();
669
672
670
    return false;
673
    return false;
671
}
674
}
672
675
673
bool MiosFileBrowser::downloadFinished(void)
676
bool MiosFileBrowser::downloadFinished(void)
674
{
677
{
675
    if( openHexEditorAfterRead ) {
678
    if( openHexEditorAfterRead ) {
676
        openHexEditor(currentReadData);
679
        openHexEditor(currentReadData);
677
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
680
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
678
        editLabel->setText(currentReadFileName, true);
681
        editLabel->setText(currentReadFileName, true);
679
    } else if( openTextEditorAfterRead ) {
682
    } else if( openTextEditorAfterRead ) {
680
        openTextEditor(currentReadData);
683
        openTextEditor(currentReadData);
681
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
684
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
682
        editLabel->setText(currentReadFileName, true);
685
        editLabel->setText(currentReadFileName, true);
683
    } else if( currentReadFileStream ) {
686
    } else if( currentReadFileStream ) {
684
        currentReadFileStream->write((uint8 *)&currentReadData.getReference(0), currentReadData.size());
687
        currentReadFileStream->write((uint8 *)&currentReadData.getReference(0), currentReadData.size());
685
        delete currentReadFileStream;
688
        delete currentReadFileStream;
686
        statusLabel->setText(T("Saved ") + currentReadFile.getFullPathName(), true);
689
        statusLabel->setText(T("Saved ") + currentReadFile.getFullPathName(), true);
687
690
688
        // try next file (if there is still another selection
691
        // try next file (if there is still another selection
689
        downloadFileSelection(++transferSelectionCtr);
692
        downloadFileSelection(++transferSelectionCtr);
690
    }
693
    }
691
694
692
    return true;
695
    return true;
693
}
696
}
694
697
695
//==============================================================================
698
//==============================================================================
696
bool MiosFileBrowser::deleteFileSelection(unsigned selection)
699
bool MiosFileBrowser::deleteFileSelection(unsigned selection)
697
{
700
{
698
    treeView->setEnabled(false);
701
    treeView->setEnabled(false);
699
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
702
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
700
703
701
    if( selectedItem ) {
704
    if( selectedItem ) {
702
        String fileName(selectedItem->getUniqueName());
705
        String fileName(selectedItem->getUniqueName());
703
        if( AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
706
        if( AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
704
                                         T("Removing ") + fileName,
707
                                         T("Removing ") + fileName,
705
                                         T("Do you really want to remove\n") + fileName + T("?"),
708
                                         T("Do you really want to remove\n") + fileName + T("?"),
706
                                         T("Remove"),
709
                                         T("Remove"),
707
                                         T("Cancel")) ) {
710
                                         T("Cancel")) ) {
708
            disableFileButtons();
711
            disableFileButtons();
709
            sendCommand(T("del ") + fileName);
712
            sendCommand(T("del ") + fileName);
710
            return true;
713
            return true;
711
        }
714
        }
712
    }
715
    }
713
716
714
    // operation finished
717
    // operation finished
715
    requestUpdateTreeView();
718
    requestUpdateTreeView();
716
719
717
    return false;
720
    return false;
718
}
721
}
719
722
720
bool MiosFileBrowser::deleteFinished(void)
723
bool MiosFileBrowser::deleteFinished(void)
721
{
724
{
722
    statusLabel->setText(T("File has been removed!"), true);
725
    statusLabel->setText(T("File has been removed!"), true);
723
726
724
    // try next file (if there is still another selection
727
    // try next file (if there is still another selection
725
    deleteFileSelection(++transferSelectionCtr);
728
    deleteFileSelection(++transferSelectionCtr);
726
729
727
    return true;
730
    return true;
728
}
731
}
729
732
730
//==============================================================================
733
//==============================================================================
731
bool MiosFileBrowser::createDir(void)
734
bool MiosFileBrowser::createDir(void)
732
{
735
{
733
    AlertWindow enterName(T("Creating new Directory"),
736
    AlertWindow enterName(T("Creating new Directory"),
734
                          T("Please enter directory name:"),
737
                          T("Please enter directory name:"),
735
                          AlertWindow::QuestionIcon);
738
                          AlertWindow::QuestionIcon);
736
739
737
    enterName.addButton(T("Create"), 1);
740
    enterName.addButton(T("Create"), 1);
738
    enterName.addButton(T("Cancel"), 0);
741
    enterName.addButton(T("Cancel"), 0);
739
    enterName.addTextEditor(T("Name"), String::empty);
742
    enterName.addTextEditor(T("Name"), String::empty);
740
743
741
    if( enterName.runModalLoop() ) {
744
    if( enterName.runModalLoop() ) {
742
        String name(enterName.getTextEditorContents(T("Name")));
745
        String name(enterName.getTextEditorContents(T("Name")));
743
        if( name.length() ) {
746
        if( name.length() ) {
744
            if( name[0] == '/' )
747
            if( name[0] == '/' )
745
                sendCommand(T("mkdir ") + name);
748
                sendCommand(T("mkdir ") + name);
746
            else
749
            else
747
                sendCommand(T("mkdir ") + getSelectedPath() + name);
750
                sendCommand(T("mkdir ") + getSelectedPath() + name);
748
        }        
751
        }        
749
    }
752
    }
750
753
751
    return false;
754
    return false;
752
}
755
}
753
756
754
bool MiosFileBrowser::createDirFinished(void)
757
bool MiosFileBrowser::createDirFinished(void)
755
{
758
{
756
    statusLabel->setText(T("Directory has been created!"), true);
759
    statusLabel->setText(T("Directory has been created!"), true);
757
760
758
    requestUpdateTreeView();
761
    requestUpdateTreeView();
759
762
760
    return true;
763
    return true;
761
}
764
}
762
765
763
//==============================================================================
766
//==============================================================================
764
bool MiosFileBrowser::createFile(void)
767
bool MiosFileBrowser::createFile(void)
765
{
768
{
766
    AlertWindow enterName(T("Creating new File"),
769
    AlertWindow enterName(T("Creating new File"),
767
                          T("Please enter filename:"),
770
                          T("Please enter filename:"),
768
                          AlertWindow::QuestionIcon);
771
                          AlertWindow::QuestionIcon);
769
772
770
    enterName.addButton(T("Create"), 1);
773
    enterName.addButton(T("Create"), 1);
771
    enterName.addButton(T("Cancel"), 0);
774
    enterName.addButton(T("Cancel"), 0);
772
    enterName.addTextEditor(T("Name"), String::empty);
775
    enterName.addTextEditor(T("Name"), String::empty);
773
776
774
    if( enterName.runModalLoop() ) {
777
    if( enterName.runModalLoop() ) {
775
        String name(enterName.getTextEditorContents(T("Name")));
778
        String name(enterName.getTextEditorContents(T("Name")));
776
        if( name.length() ) {
779
        if( name.length() ) {
777
            Array<uint8> emptyBuffer;
780
            Array<uint8> emptyBuffer;
778
            if( name[0] == '/' )
781
            if( name[0] == '/' )
779
                return uploadBuffer(name, emptyBuffer);
782
                return uploadBuffer(name, emptyBuffer);
780
            else
783
            else
781
                return uploadBuffer(getSelectedPath() + name, emptyBuffer);
784
                return uploadBuffer(getSelectedPath() + name, emptyBuffer);
782
        }        
785
        }        
783
    }
786
    }
784
787
785
    return false;
788
    return false;
786
}
789
}
787
790
788
//==============================================================================
791
//==============================================================================
789
bool MiosFileBrowser::uploadFile(void)
792
bool MiosFileBrowser::uploadFile(void)
790
{
793
{
791
    // restore default path
794
    // restore default path
792
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
795
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
793
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
796
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
794
    if( propertiesFile ) {
797
    if( propertiesFile ) {
795
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
798
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
796
    }
799
    }
797
    File defaultPathFile(defaultPath);
800
    File defaultPathFile(defaultPath);
798
    FileChooser myChooser(T("Upload File to Core"), defaultPathFile);
801
    FileChooser myChooser(T("Upload File to Core"), defaultPathFile);
799
    if( !myChooser.browseForFileToOpen() ) {
802
    if( !myChooser.browseForFileToOpen() ) {
800
        return false;
803
        return false;
801
    } else {
804
    } else {
802
        File inFile(myChooser.getResult());
805
        File inFile(myChooser.getResult());
803
806
804
        // store default path
807
        // store default path
805
        if( propertiesFile ) {
808
        if( propertiesFile ) {
806
            propertiesFile->setValue(T("defaultFilebrowserPath"), inFile.getParentDirectory().getFullPathName());
809
            propertiesFile->setValue(T("defaultFilebrowserPath"), inFile.getParentDirectory().getFullPathName());
807
        }
810
        }
808
811
809
        FileInputStream *inFileStream = inFile.createInputStream();
812
        FileInputStream *inFileStream = inFile.createInputStream();
810
        if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
813
        if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
811
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
814
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
812
                                        T("The file ") + inFile.getFileName(),
815
                                        T("The file ") + inFile.getFileName(),
813
                                        T("doesn't exist!"),
816
                                        T("doesn't exist!"),
814
                                        String::empty);
817
                                        String::empty);
815
        } else if( inFileStream->isExhausted() ) { // || !inFileStream->getTotalLength() -> disabled, we also want to handle zero-length files
818
        } else if( inFileStream->isExhausted() ) { // || !inFileStream->getTotalLength() -> disabled, we also want to handle zero-length files
816
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
819
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
817
                                        T("The file ") + inFile.getFileName(),
820
                                        T("The file ") + inFile.getFileName(),
818
                                        T("can't be read!"),
821
                                        T("can't be read!"),
819
                                        String::empty);
822
                                        String::empty);
820
        } else {
823
        } else {
821
            disableFileButtons();
824
            disableFileButtons();
822
825
823
            uint64 size = inFileStream->getTotalLength();
826
            uint64 size = inFileStream->getTotalLength();
824
            uint8 *buffer = (uint8 *)juce_malloc(size);
827
            uint8 *buffer = (uint8 *)juce_malloc(size);
825
            size = inFileStream->read(buffer, size);
828
            size = inFileStream->read(buffer, size);
826
            //currentWriteData.resize(currentWriteSize); // doesn't exist in Juce 1.53
829
            //currentWriteData.resize(currentWriteSize); // doesn't exist in Juce 1.53
827
            Array<uint8> tmp(buffer, size);
830
            Array<uint8> tmp(buffer, size);
828
            juce_free(buffer);
831
            juce_free(buffer);
829
            uploadBuffer(getSelectedPath() + inFile.getFileName(), tmp);
832
            uploadBuffer(getSelectedPath() + inFile.getFileName(), tmp);
830
        }
833
        }
831
834
832
        if( inFileStream )
835
        if( inFileStream )
833
            delete inFileStream;
836
            delete inFileStream;
834
    }
837
    }
835
838
836
    return true;
839
    return true;
837
}
840
}
838
841
839
bool MiosFileBrowser::uploadBuffer(String filename, const Array<uint8>& buffer)
842
bool MiosFileBrowser::uploadBuffer(String filename, const Array<uint8>& buffer)
840
{
843
{
841
    currentWriteFileName = filename;
844
    currentWriteFileName = filename;
842
    currentWriteData = buffer;
845
    currentWriteData = buffer;
843
    currentWriteSize = buffer.size();
846
    currentWriteSize = buffer.size();
844
847
845
    statusLabel->setText(T("Uploading ") + currentWriteFileName + T(" (") + String(currentWriteSize) + T(" bytes)"), true);
848
    statusLabel->setText(T("Uploading ") + currentWriteFileName + T(" (") + String(currentWriteSize) + T(" bytes)"), true);
846
849
847
    currentWriteInProgress = true;
850
    currentWriteInProgress = true;
848
    currentWriteError = false;
851
    currentWriteError = false;
849
    currentWriteFirstBlockOffset = 0;
852
    currentWriteFirstBlockOffset = 0;
850
    currentWriteBlockCtr = writeBlockCtrDefault;
853
    currentWriteBlockCtr = writeBlockCtrDefault;
851
    currentWriteStartTime = Time::currentTimeMillis();
854
    currentWriteStartTime = Time::currentTimeMillis();
852
    sendCommand(T("write ") + currentWriteFileName + T(" ") + String(currentWriteSize));
855
    sendCommand(T("write ") + currentWriteFileName + T(" ") + String(currentWriteSize));
853
    startTimer(5000);
856
    startTimer(5000);
854
857
855
    return true;
858
    return true;
856
}
859
}
857
860
858
bool MiosFileBrowser::uploadFinished(void)
861
bool MiosFileBrowser::uploadFinished(void)
859
{
862
{
860
    currentWriteInProgress = false;
863
    currentWriteInProgress = false;
861
    String extraText;
864
    String extraText;
862
865
863
    // finished edit operation?
866
    // finished edit operation?
864
    if( openHexEditorAfterRead || openTextEditorAfterRead ) {
867
    if( openHexEditorAfterRead || openTextEditorAfterRead ) {
865
#if 0
868
#if 0
866
        openHexEditorAfterRead = false;
869
        openHexEditorAfterRead = false;
867
        openTextEditorAfterRead = false;
870
        openTextEditorAfterRead = false;
868
        hexEditor->clear();
871
        hexEditor->clear();
869
        hexEditor->setReadOnly(true);
872
        hexEditor->setReadOnly(true);
870
        textEditor->clear();
873
        textEditor->clear();
871
        textEditor->setReadOnly(true);
874
        textEditor->setReadOnly(true);
872
        editLabel->setText(String::empty, true);
875
        editLabel->setText(String::empty, true);
873
#else
876
#else
874
        extraText = T(" - you can continue editing; click CANCEL to close editor!");
877
        extraText = T(" - you can continue editing; click CANCEL to close editor!");
875
        // don't close editor
878
        // don't close editor
876
#endif
879
#endif
877
    }
880
    }
878
881
879
    uint32 currentWriteFinished = Time::currentTimeMillis();
882
    uint32 currentWriteFinished = Time::currentTimeMillis();
880
    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
883
    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
881
    float dataRate = ((float)currentWriteSize/1000.0) / downloadTime;
884
    float dataRate = ((float)currentWriteSize/1000.0) / downloadTime;
882
885
883
886
884
    statusLabel->setText(T("Upload of ") + currentWriteFileName +
887
    statusLabel->setText(T("Upload of ") + currentWriteFileName +
885
                         T(" (") + String(currentWriteSize) + T(" bytes) completed in ") +
888
                         T(" (") + String(currentWriteSize) + T(" bytes) completed in ") +
886
                         String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate) +
889
                         String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate) +
887
                         extraText, true);
890
                         extraText, true);
888
891
889
#if 0 // not required
892
#if 0 // not required
890
    requestUpdateTreeView();
893
    requestUpdateTreeView();
891
#else
894
#else
892
    if( !openHexEditorAfterRead && !openTextEditorAfterRead ) {
895
    if( !openHexEditorAfterRead && !openTextEditorAfterRead ) {
893
        enableFileButtons();
896
        enableFileButtons();
894
    }
897
    }
895
#endif
898
#endif
896
899
897
900
898
    return true;
901
    return true;
899
}
902
}
900
903
901
//==============================================================================
904
//==============================================================================
902
void MiosFileBrowser::timerCallback()
905
void MiosFileBrowser::timerCallback()
903
{
906
{
904
    if( currentReadInProgress ) {
907
    if( currentReadInProgress ) {
905
        if( currentReadError ) {
908
        if( currentReadError ) {
906
            statusLabel->setText(T("Invalid response from MIOS32 core during read operation!"), true);
909
            statusLabel->setText(T("Invalid response from MIOS32 core during read operation!"), true);
907
        } else {
910
        } else {
908
            statusLabel->setText(T("No response from MIOS32 core during read operation!"), true);
911
            statusLabel->setText(T("No response from MIOS32 core during read operation!"), true);
909
        }
912
        }
910
    } else {
913
    } else {
911
        statusLabel->setText(T("No response from MIOS32 core!"), true);
914
        statusLabel->setText(T("No response from MIOS32 core!"), true);
912
    }
915
    }
913
}
916
}
914
917
915
//==============================================================================
918
//==============================================================================
916
void MiosFileBrowser::sendCommand(const String& command)
919
void MiosFileBrowser::sendCommand(const String& command)
917
{
920
{
918
    Array<uint8> dataArray = SysexHelper::createMios32DebugMessage(miosStudio->uploadHandler->getDeviceId());
921
    Array<uint8> dataArray = SysexHelper::createMios32DebugMessage(miosStudio->uploadHandler->getDeviceId());
919
    dataArray.add(0x01); // filebrowser string
922
    dataArray.add(0x01); // filebrowser string
920
    for(int i=0; i<command.length(); ++i)
923
    for(int i=0; i<command.length(); ++i)
921
        dataArray.add(command[i] & 0x7f);
924
        dataArray.add(command[i] & 0x7f);
922
    dataArray.add('\n');
925
    dataArray.add('\n');
923
    dataArray.add(0xf7);
926
    dataArray.add(0xf7);
924
    MidiMessage message = SysexHelper::createMidiMessage(dataArray);
927
    MidiMessage message = SysexHelper::createMidiMessage(dataArray);
925
    miosStudio->sendMidiMessage(message);
928
    miosStudio->sendMidiMessage(message);
926
    startTimer(5000);
929
    startTimer(5000);
927
}
930
}
928
931
929
//==============================================================================
932
//==============================================================================
930
void MiosFileBrowser::receiveCommand(const String& command)
933
void MiosFileBrowser::receiveCommand(const String& command)
931
{
934
{
932
    String statusMessage;
935
    String statusMessage;
933
936
934
    stopTimer(); // will be restarted if required
937
    stopTimer(); // will be restarted if required
935
938
936
    if( command.length() ) {
939
    if( command.length() ) {
937
        switch( command[0] ) {
940
        switch( command[0] ) {
938
941
939
        ////////////////////////////////////////////////////////////////////
942
        ////////////////////////////////////////////////////////////////////
940
        case '?': {
943
        case '?': {
941
            statusMessage = String(T("Command not supported by MIOS32 application - please check if a firmware update is available!"));
944
            statusMessage = String(T("Command not supported by MIOS32 application - please check if a firmware update is available!"));
942
        } break;
945
        } break;
943
946
944
        ////////////////////////////////////////////////////////////////////
947
        ////////////////////////////////////////////////////////////////////
945
        case 'D': {
948
        case 'D': {
946
            if( command[1] == '!' ) {
949
            if( command[1] == '!' ) {
947
                statusMessage = String(T("SD Card not mounted!"));
950
                statusMessage = String(T("SD Card not mounted!"));
948
            } else if( command[1] == '-' ) {
951
            } else if( command[1] == '-' ) {
949
                statusMessage = String(T("Failed to access directory!"));
952
                statusMessage = String(T("Failed to access directory!"));
950
            } else {
953
            } else {
951
                //statusMessage = String(T("Received directory structure."));
954
                //statusMessage = String(T("Received directory structure."));
952
955
953
                int posStartName = 2;
956
                int posStartName = 2;
954
                for(int pos=2; pos<command.length(); ++pos) {
957
                for(int pos=2; pos<command.length(); ++pos) {
955
                    if( command[pos] == 'F' || command[pos] == 'D' ) {
958
                    if( command[pos] == 'F' || command[pos] == 'D' ) {
956
                        for(++pos; pos < command.length() && command[pos] != ','; ++pos);
959
                        for(++pos; pos < command.length() && command[pos] != ','; ++pos);
957
                        String fileName(command.substring(posStartName, pos));
960
                        String fileName(command.substring(posStartName, pos));
958
                        //std::cout << "XXX " << fileName << std::endl;
961
                        //std::cout << "XXX " << fileName << std::endl;
959
                        if( fileName[0] == 'F' ) {
962
                        if( fileName[0] == 'F' ) {
960
                            currentDirItem->createChild(currentDirPath, fileName.substring(1), false);
963
                            currentDirItem->createChild(currentDirPath, fileName.substring(1), false);
961
                        } else if( fileName[0] == 'D' ) {
964
                        } else if( fileName[0] == 'D' ) {
962
                            currentDirFetchItems.add(currentDirItem->createChild(currentDirPath, fileName.substring(1), true));
965
                            currentDirFetchItems.add(currentDirItem->createChild(currentDirPath, fileName.substring(1), true));
963
                        } else {
966
                        } else {
964
                            std::cout << "INVALID Response: " << currentDirPath << fileName << std::endl;
967
                            std::cout << "INVALID Response: " << currentDirPath << fileName << std::endl;
965
                            statusMessage = String(T("Invalid Response!"));
968
                            statusMessage = String(T("Invalid Response!"));
966
                            break;
969
                            break;
967
                        }
970
                        }
968
                        posStartName = pos+1;
971
                        posStartName = pos+1;
969
                    } else {
972
                    } else {
970
                        statusMessage = String(T("Invalid Response!"));
973
                        statusMessage = String(T("Invalid Response!"));
971
                        break;
974
                        break;
972
                    }
975
                    }
973
                }
976
                }
974
            }
977
            }
975
978
976
            // do we have to fetch some additional subdirectories?
979
            // do we have to fetch some additional subdirectories?
977
            if( currentDirFetchItems.size() ) {
980
            if( currentDirFetchItems.size() ) {
978
                currentDirItem = currentDirFetchItems.remove(0);
981
                currentDirItem = currentDirFetchItems.remove(0);
979
                if( currentDirItem->parentPath.compare(T("/")) == 0 )
982
                if( currentDirItem->parentPath.compare(T("/")) == 0 )
980
                    currentDirPath = currentDirItem->parentPath + currentDirItem->name;
983
                    currentDirPath = currentDirItem->parentPath + currentDirItem->name;
981
                else
984
                else
982
                    currentDirPath = currentDirItem->parentPath + T("/") + currentDirItem->name;
985
                    currentDirPath = currentDirItem->parentPath + T("/") + currentDirItem->name;
983
                //std::cout << "Fetch " << currentDirPath << std::endl;
986
                //std::cout << "Fetch " << currentDirPath << std::endl;
984
                sendCommand(T("dir ") + currentDirPath);
987
                sendCommand(T("dir ") + currentDirPath);
985
            } else {
988
            } else {
986
                updateTreeView(true);
989
                updateTreeView(true);
987
            }
990
            }
988
        } break;
991
        } break;
989
992
990
        ////////////////////////////////////////////////////////////////////
993
        ////////////////////////////////////////////////////////////////////
991
        case 'R': {
994
        case 'R': {
992
            if( command[1] == '!' ) {
995
            if( command[1] == '!' ) {
993
                statusMessage = String(T("SD Card not mounted!"));
996
                statusMessage = String(T("SD Card not mounted!"));
994
            } else if( command[1] == '-' ) {
997
            } else if( command[1] == '-' ) {
995
                statusMessage = String(T("Failed to access " + currentReadFileName + "!"));
998
                statusMessage = String(T("Failed to access " + currentReadFileName + "!"));
996
            } else {
999
            } else {
997
                currentReadSize = (command.substring(1)).getIntValue();
1000
                currentReadSize = (command.substring(1)).getIntValue();
998
                currentReadData.clear();
1001
                currentReadData.clear();
999
                if( currentReadSize ) {
1002
                if( currentReadSize ) {
1000
                    statusMessage = String(T("Receiving ") + currentReadFileName + T(" with ") + String(currentReadSize) + T(" bytes."));
1003
                    statusMessage = String(T("Receiving ") + currentReadFileName + T(" with ") + String(currentReadSize) + T(" bytes."));
1001
                    currentReadInProgress = true;
1004
                    currentReadInProgress = true;
1002
                    currentReadError = false;
1005
                    currentReadError = false;
1003
                    currentReadStartTime = Time::currentTimeMillis();
1006
                    currentReadStartTime = Time::currentTimeMillis();
1004
                    startTimer(5000);
1007
                    startTimer(5000);
1005
                } else {
1008
                } else {
1006
                    statusMessage = String(currentReadFileName + T(" is empty!"));
1009
                    statusMessage = String(currentReadFileName + T(" is empty!"));
1007
                    // ok, we accept this to edit zero-length files
1010
                    // ok, we accept this to edit zero-length files
1008
                    // fake transfer:
1011
                    // fake transfer:
1009
                    currentReadInProgress = false;
1012
                    currentReadInProgress = false;
1010
                    currentReadData.clear();
1013
                    currentReadData.clear();
1011
                    statusLabel->setText(statusMessage, true);
1014
                    statusLabel->setText(statusMessage, true);
1012
                    downloadFinished();
1015
                    downloadFinished();
1013
                    statusMessage = String::empty; // status has been updated by downloadFinished()
1016
                    statusMessage = String::empty; // status has been updated by downloadFinished()
1014
                }
1017
                }
1015
            }
1018
            }
1016
        } break;
1019
        } break;
1017
1020
1018
        ////////////////////////////////////////////////////////////////////
1021
        ////////////////////////////////////////////////////////////////////
1019
        case 'r': {
1022
        case 'r': {
1020
            if( !currentReadInProgress ) {
1023
            if( !currentReadInProgress ) {
1021
                statusMessage = String(T("There is a read operation in progress - please wait!"));
1024
                statusMessage = String(T("There is a read operation in progress - please wait!"));
1022
            } else {
1025
            } else {
1023
                String strAddress = command.substring(1, 9);
1026
                String strAddress = command.substring(1, 9);
1024
                String strPayload = command.substring(10);
1027
                String strPayload = command.substring(10);
1025
1028
1026
                unsigned address = strAddress.getHexValue32();
1029
                unsigned address = strAddress.getHexValue32();
1027
1030
1028
                if( address >= currentReadSize ) {
1031
                if( address >= currentReadSize ) {
1029
                    statusMessage = String(currentReadFileName + T(" received invalid payload!"));
1032
                    statusMessage = String(currentReadFileName + T(" received invalid payload!"));
1030
                    currentReadError = true;
1033
                    currentReadError = true;
1031
                } else {
1034
                } else {
1032
                    for(int pos=0; pos<strPayload.length(); pos+=2) {
1035
                    for(int pos=0; pos<strPayload.length(); pos+=2) {
1033
                        uint8 b = (strPayload.substring(pos, pos+2)).getHexValue32();
1036
                        uint8 b = (strPayload.substring(pos, pos+2)).getHexValue32();
1034
                        currentReadData.set(address + (pos/2), b);
1037
                        currentReadData.set(address + (pos/2), b);
1035
                    }
1038
                    }
1036
1039
1037
                    unsigned receivedSize = currentReadData.size();
1040
                    unsigned receivedSize = currentReadData.size();
1038
                    uint32 currentReadFinished = Time::currentTimeMillis();
1041
                    uint32 currentReadFinished = Time::currentTimeMillis();
1039
                    float downloadTime = (float)(currentReadFinished-currentReadStartTime) / 1000.0;
1042
                    float downloadTime = (float)(currentReadFinished-currentReadStartTime) / 1000.0;
1040
                    float dataRate = ((float)receivedSize/1000.0) / downloadTime;
1043
                    float dataRate = ((float)receivedSize/1000.0) / downloadTime;
1041
                    if( receivedSize >= currentReadSize ) {
1044
                    if( receivedSize >= currentReadSize ) {
1042
                        statusMessage = String(T("Download of ") + currentReadFileName +
1045
                        statusMessage = String(T("Download of ") + currentReadFileName +
1043
                                               T(" (") + String(receivedSize) + T(" bytes) completed in ") +
1046
                                               T(" (") + String(receivedSize) + T(" bytes) completed in ") +
1044
                                               String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
1047
                                               String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
1045
                        currentReadInProgress = false;
1048
                        currentReadInProgress = false;
1046
1049
1047
                        statusLabel->setText(statusMessage, true);
1050
                        statusLabel->setText(statusMessage, true);
1048
                        downloadFinished();
1051
                        downloadFinished();
1049
                        statusMessage = String::empty; // status has been updated by downloadFinished()
1052
                        statusMessage = String::empty; // status has been updated by downloadFinished()
1050
                    } else {
1053
                    } else {
1051
                        statusMessage = String(T("Downloading ") + currentReadFileName + T(": ") +
1054
                        statusMessage = String(T("Downloading ") + currentReadFileName + T(": ") +
1052
                                               String(receivedSize) + T(" bytes received") +
1055
                                               String(receivedSize) + T(" bytes received") +
1053
                                               String::formatted(T(" (%d%%, %2.1f kb/s)"),
1056
                                               String::formatted(T(" (%d%%, %2.1f kb/s)"),
1054
                                                                 (int)(100.0*(float)receivedSize/(float)currentReadSize),
1057
                                                                 (int)(100.0*(float)receivedSize/(float)currentReadSize),
1055
                                                                 dataRate));
1058
                                                                 dataRate));
1056
                        startTimer(5000);
1059
                        startTimer(5000);
1057
                    }
1060
                    }
1058
                }
1061
                }
1059
            }
1062
            }
1060
        } break;
1063
        } break;
1061
1064
1062
        ////////////////////////////////////////////////////////////////////
1065
        ////////////////////////////////////////////////////////////////////
1063
        case 'W': {
1066
        case 'W': {
1064
            if( currentWriteError ) {
1067
            if( currentWriteError ) {
1065
                // ignore
1068
                // ignore
1066
            } else if( !currentWriteInProgress ) {
1069
            } else if( !currentWriteInProgress ) {
1067
                statusMessage = String(T("There is a write operation in progress - please wait!"));
1070
                statusMessage = String(T("There is a write operation in progress - please wait!"));
1068
            } else if( command[1] == '!' ) {
1071
            } else if( command[1] == '!' ) {
1069
                statusMessage = String(T("SD Card not mounted!"));
1072
                statusMessage = String(T("SD Card not mounted!"));
1070
            } else if( command[1] == '-' ) {
1073
            } else if( command[1] == '-' ) {
1071
                statusMessage = String(T("Failed to access " + currentWriteFileName + "!"));
1074
                statusMessage = String(T("Failed to access " + currentWriteFileName + "!"));
1072
            } else if( command[1] == '~' ) {
1075
            } else if( command[1] == '~' ) {
1073
                statusMessage = String(T("FATAL: invalid parameters for write operation!"));
1076
                statusMessage = String(T("FATAL: invalid parameters for write operation!"));
1074
            } else if( command[1] == '#' ) {
1077
            } else if( command[1] == '#' ) {
1075
                uploadFinished();
1078
                uploadFinished();
1076
                statusMessage = String::empty; // status has been updated by uploadFinished()
1079
                statusMessage = String::empty; // status has been updated by uploadFinished()
1077
            } else {
1080
            } else {
1078
                unsigned addressOffset = command.substring(1).getHexValue32();
1081
                unsigned addressOffset = command.substring(1).getHexValue32();
1079
1082
1080
                if( currentWriteBlockCtr < writeBlockCtrDefault ) {
1083
                if( currentWriteBlockCtr < writeBlockCtrDefault ) {
1081
                    // check for valid response
1084
                    // check for valid response
1082
                    unsigned expectedOffset = currentWriteFirstBlockOffset + (writeBlockSizeDefault*(currentWriteBlockCtr+1));
1085
                    unsigned expectedOffset = currentWriteFirstBlockOffset + (writeBlockSizeDefault*(currentWriteBlockCtr+1));
1083
                    if( addressOffset != expectedOffset ) {
1086
                    if( addressOffset != expectedOffset ) {
1084
                        currentWriteError = true;
1087
                        currentWriteError = true;
1085
                        statusLabel->setText(String::formatted(T("ERROR: the application has requested file position 0x%08X, but filebrowser expected 0x%08X! Please check with TK!"), addressOffset, expectedOffset), true);
1088
                        statusLabel->setText(String::formatted(T("ERROR: the application has requested file position 0x%08X, but filebrowser expected 0x%08X! Please check with TK!"), addressOffset, expectedOffset), true);
1086
                    } else {
1089
                    } else {
1087
                        ++currentWriteBlockCtr; // block received
1090
                        ++currentWriteBlockCtr; // block received
1088
                    }                    
1091
                    }                    
1089
                }
1092
                }
1090
1093
1091
                // new burst?
1094
                // new burst?
1092
                if( currentWriteBlockCtr >= writeBlockCtrDefault ) {
1095
                if( currentWriteBlockCtr >= writeBlockCtrDefault ) {
1093
                    currentWriteFirstBlockOffset = addressOffset;
1096
                    currentWriteFirstBlockOffset = addressOffset;
1094
                    currentWriteBlockCtr = 0;
1097
                    currentWriteBlockCtr = 0;
1095
1098
1096
                    for(unsigned block=0; block<writeBlockCtrDefault; ++block, addressOffset += writeBlockSizeDefault) {
1099
                    for(unsigned block=0; block<writeBlockCtrDefault; ++block, addressOffset += writeBlockSizeDefault) {
1097
                        String writeCommand(String::formatted(T("writedata %08X "), addressOffset));
1100
                        String writeCommand(String::formatted(T("writedata %08X "), addressOffset));
1098
                        for(int i=0; i<writeBlockSizeDefault && (i+addressOffset)<currentWriteSize; ++i) {
1101
                        for(int i=0; i<writeBlockSizeDefault && (i+addressOffset)<currentWriteSize; ++i) {
1099
                            writeCommand += String::formatted(T("%02X"), currentWriteData[addressOffset + i]);
1102
                            writeCommand += String::formatted(T("%02X"), currentWriteData[addressOffset + i]);
1100
                        }
1103
                        }
1101
                        sendCommand(writeCommand);
1104
                        sendCommand(writeCommand);
1102
1105
1103
                        if( (writeBlockSizeDefault+addressOffset) >= currentWriteSize )
1106
                        if( (writeBlockSizeDefault+addressOffset) >= currentWriteSize )
1104
                            break;
1107
                            break;
1105
                    }
1108
                    }
1106
1109
1107
                    uint32 currentWriteFinished = Time::currentTimeMillis();
1110
                    uint32 currentWriteFinished = Time::currentTimeMillis();
1108
                    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
1111
                    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
1109
                    float dataRate = ((float)addressOffset/1000.0) / downloadTime;
1112
                    float dataRate = ((float)addressOffset/1000.0) / downloadTime;
1110
1113
1111
                    statusMessage = String(T("Uploading ") + currentWriteFileName + T(": ") +
1114
                    statusMessage = String(T("Uploading ") + currentWriteFileName + T(": ") +
1112
                                           String(addressOffset) + T(" bytes transmitted") +
1115
                                           String(addressOffset) + T(" bytes transmitted") +
1113
                                           String::formatted(T(" (%d%%, %2.1f kb/s)"),
1116
                                           String::formatted(T(" (%d%%, %2.1f kb/s)"),
1114
                                                             (int)(100.0*(float)addressOffset/(float)currentWriteSize),
1117
                                                             (int)(100.0*(float)addressOffset/(float)currentWriteSize),
1115
                                                             dataRate));
1118
                                                             dataRate));
1116
                    startTimer(5000);
1119
                    startTimer(5000);
1117
                }
1120
                }
1118
            }
1121
            }
1119
        } break;
1122
        } break;
1120
1123
1121
1124
1122
        ////////////////////////////////////////////////////////////////////
1125
        ////////////////////////////////////////////////////////////////////
1123
        case 'M': {
1126
        case 'M': {
1124
            if( command[1] == '!' ) {
1127
            if( command[1] == '!' ) {
1125
                statusMessage = String(T("SD Card not mounted!"));
1128
                statusMessage = String(T("SD Card not mounted!"));
1126
            } else if( command[1] == '-' ) {
1129
            } else if( command[1] == '-' ) {
1127
                statusMessage = String(T("Failed to create directory!"));
1130
                statusMessage = String(T("Failed to create directory!"));
1128
            } else if( command[1] == '#' ) {
1131
            } else if( command[1] == '#' ) {
1129
                createDirFinished();
1132
                createDirFinished();
1130
                statusMessage = String::empty; // status has been updated by createDirFinished()
1133
                statusMessage = String::empty; // status has been updated by createDirFinished()
1131
            } else {
1134
            } else {
1132
                statusMessage = String(T("Unsupported response from mkdir command!"));
1135
                statusMessage = String(T("Unsupported response from mkdir command!"));
1133
            }
1136
            }
1134
        } break;
1137
        } break;
1135
1138
1136
1139
1137
        ////////////////////////////////////////////////////////////////////
1140
        ////////////////////////////////////////////////////////////////////
1138
        case 'X': {
1141
        case 'X': {
1139
            if( command[1] == '!' ) {
1142
            if( command[1] == '!' ) {
1140
                statusMessage = String(T("SD Card not mounted!"));
1143
                statusMessage = String(T("SD Card not mounted!"));
1141
            } else if( command[1] == '-' ) {
1144
            } else if( command[1] == '-' ) {
1142
                statusMessage = String(T("Failed to delete file!"));
1145
                statusMessage = String(T("Failed to delete file!"));
1143
            } else if( command[1] == '#' ) {
1146
            } else if( command[1] == '#' ) {
1144
                deleteFinished();
1147
                deleteFinished();
1145
                statusMessage = String::empty; // status has been updated by deleteFinished()
1148
                statusMessage = String::empty; // status has been updated by deleteFinished()
1146
            } else {
1149
            } else {
1147
                statusMessage = String(T("Unsupported response from del command!"));
1150
                statusMessage = String(T("Unsupported response from del command!"));
1148
            }
1151
            }
1149
        } break;
1152
        } break;
1150
1153
1151
1154
1152
        ////////////////////////////////////////////////////////////////////
1155
        ////////////////////////////////////////////////////////////////////
1153
        default:
1156
        default:
1154
            statusMessage = String(T("Received unsupported Filebrowser Command! Please update your MIOS Studio installation!"));
1157
            statusMessage = String(T("Received unsupported Filebrowser Command! Please update your MIOS Studio installation!"));
1155
        }
1158
        }
1156
    }
1159
    }
1157
1160
1158
    if( statusMessage.length() ) {
1161
    if( statusMessage.length() ) {
1159
        statusLabel->setText(statusMessage, true);
1162
        statusLabel->setText(statusMessage, true);
1160
    }
1163
    }
1161
}
1164
}
1162
1165
1163
//==============================================================================
1166
//==============================================================================
1164
void MiosFileBrowser::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
1167
void MiosFileBrowser::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
1165
{
1168
{
1166
    uint8 *data = (uint8 *)message.getRawData();
1169
    uint8 *data = (uint8 *)message.getRawData();
1167
    uint32 size = message.getRawDataSize();
1170
    uint32 size = message.getRawDataSize();
1168
    int messageOffset = 0;
1171
    int messageOffset = 0;
1169
1172
1170
    bool messageReceived = false;
1173
    bool messageReceived = false;
1171
    if( runningStatus == 0xf0 &&
1174
    if( runningStatus == 0xf0 &&
1172
        SysexHelper::isValidMios32DebugMessage(data, size, -1) &&
1175
        SysexHelper::isValidMios32DebugMessage(data, size, -1) &&
1173
        data[7] == 0x41 ) {
1176
        data[7] == 0x41 ) {
1174
            messageOffset = 8;
1177
            messageOffset = 8;
1175
            messageReceived = true;
1178
            messageReceived = true;
1176
    } else if( runningStatus == 0xf0 &&
1179
    } else if( runningStatus == 0xf0 &&
1177
        SysexHelper::isValidMios32Error(data, size, -1) &&
1180
        SysexHelper::isValidMios32Error(data, size, -1) &&
1178
        data[7] == 0x10 ) {
1181
        data[7] == 0x10 ) {
1179
        stopTimer();
1182
        stopTimer();
1180
        statusLabel->setText(T("Filebrowser access not implemented by this application!"), true);
1183
        statusLabel->setText(T("Filebrowser access not implemented by this application!"), true);
1181
    }
1184
    }
1182
1185
1183
    if( messageReceived ) {
1186
    if( messageReceived ) {
1184
        String command;
1187
        String command;
1185
1188
1186
        for(int i=messageOffset; i<size; ++i) {
1189
        for(int i=messageOffset; i<size; ++i) {
1187
            if( data[i] < 0x80 ) {
1190
            if( data[i] < 0x80 ) {
1188
                if( data[i] != '\n' || size < (i+1) )
1191
                if( data[i] != '\n' || size < (i+1) )
1189
                    command += String::formatted(T("%c"), data[i] & 0x7f);
1192
                    command += String::formatted(T("%c"), data[i] & 0x7f);
1190
            }
1193
            }
1191
        }
1194
        }
1192
        receiveCommand(command);
1195
        receiveCommand(command);
1193
    }
1196
    }
1194
}
1197
}
1195
 
1198