OSDN Git Service

Shiftを押しながら追加操作を行うことでフォルダを書庫に追加する機能を追加。
[tpi/lychee.git] / src / lychee / frm_main.cpp
1 /*******************************************************************************\r
2   TPI - flexible but useless plug-in framework.\r
3   Copyright (C) 2002-2009 Silky\r
4 \r
5   This library is free software; you can redistribute it and/or modify it under\r
6   the terms of the GNU Lesser General Public License as published by the Free\r
7   Software Foundation; either version 2.1 of the License, or (at your option)\r
8   any later version.\r
9 \r
10   This library is distributed in the hope that it will be useful, but WITHOUT\r
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License\r
13   for more details.\r
14 \r
15   You should have received a copy of the GNU Lesser General Public License along\r
16   with this library; if not, write to the Free Software Foundation, Inc.,\r
17   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
18 \r
19   $Id$\r
20 *******************************************************************************/\r
21 \r
22 #include "lychee.h"\r
23 \r
24 #include "frm_main.h"\r
25 #include "cls_filedroptarget.h"\r
26 #include "dlg_make.h"\r
27 #include "dlg_process.h"\r
28 #include "functions.h"\r
29 \r
30 #include <wx/arrimpl.cpp>\r
31 \r
32 WX_DEFINE_OBJARRAY(ArrayTPI_FILEINFO);\r
33 \r
34 #define SetMenuToolState(id, state) this->toolbar->EnableTool(XRCID(id), state); this->menubar->Enable(XRCID(id), state)\r
35 \r
36 //******************************************************************************\r
37 //    グローバル変数\r
38 //******************************************************************************\r
39 \r
40 wxImageList g_hIconT(16, 16), g_hIconLL(32, 32), g_hIconLS(16, 16);\r
41 int g_nSortColumn;\r
42 bool g_fSortAscend;\r
43 \r
44 //******************************************************************************\r
45 // MainFrame\r
46 //******************************************************************************\r
47 \r
48 MainFrame::MainFrame(): wxFrame()\r
49 {\r
50 }\r
51 \r
52 MainFrame::~MainFrame()\r
53 {\r
54         wxCommandEvent e;\r
55         this->OnArcClose(e);\r
56 \r
57         // 設定を記録。\r
58         if (! this->IsIconized() && ! this->IsMaximized())\r
59         {\r
60                 int a, b;\r
61                 this->GetSize(& a, & b);\r
62                 this->conf.WriteId(CONF_WINDOW_WIDTH,  a);\r
63                 this->conf.WriteId(CONF_WINDOW_HEIGHT, b);\r
64                 this->GetPosition(& a, & b);\r
65                 this->conf.WriteId(CONF_WINDOW_X, a);\r
66                 this->conf.WriteId(CONF_WINDOW_Y, b);\r
67         }\r
68         this->conf.WriteId(CONF_WINDOW_SPLITTER_POS, this->window_splitter->GetSashPosition());\r
69 \r
70         // ツールバー/ステータスバー関連。\r
71         this->conf.WriteId(CONF_WINDOW_STATUSBAR, this->statusbar->IsShown());\r
72         this->conf.WriteId(CONF_WINDOW_TOOLBAR,   this->toolbar->IsShown());\r
73 \r
74         // ListView関連。\r
75         this->conf.WriteId(CONF_LISTVIEW_SHOWMODE, this->menubar->IsChecked(XRCID("Exe_View_Icons")) ? 1 : this->menubar->IsChecked(XRCID("Exe_View_List")) ? 2 : 0);\r
76         if (this->menubar->IsChecked(XRCID("Exe_View_Details")))\r
77         {\r
78                 this->conf.WriteId(CONF_LISTVIEW_C_FILENAME, this->list_ctrl->GetColumnWidth(0));\r
79                 this->conf.WriteId(CONF_LISTVIEW_C_UNPACKED, this->list_ctrl->GetColumnWidth(1));\r
80                 this->conf.WriteId(CONF_LISTVIEW_C_PACKED,   this->list_ctrl->GetColumnWidth(2));\r
81                 this->conf.WriteId(CONF_LISTVIEW_C_RATIO,    this->list_ctrl->GetColumnWidth(3));\r
82                 this->conf.WriteId(CONF_LISTVIEW_C_METHOD,   this->list_ctrl->GetColumnWidth(4));\r
83                 this->conf.WriteId(CONF_LISTVIEW_C_ATTR,         this->list_ctrl->GetColumnWidth(5));\r
84                 this->conf.WriteId(CONF_LISTVIEW_C_LASTMOD,  this->list_ctrl->GetColumnWidth(6));\r
85                 this->conf.WriteId(CONF_LISTVIEW_C_PATH,     this->list_ctrl->GetColumnWidth(7));\r
86                 this->conf.WriteId(CONF_LISTVIEW_C_TYPE,     this->list_ctrl->GetColumnWidth(8));\r
87                 this->conf.WriteId(CONF_LISTVIEW_C_NO,       this->list_ctrl->GetColumnWidth(9));\r
88                 this->conf.WriteId(CONF_LISTVIEW_C_COMMENT,  this->list_ctrl->GetColumnWidth(10));\r
89                 this->conf.WriteId(CONF_LISTVIEW_S_COLUMN,   g_nSortColumn);\r
90                 this->conf.WriteId(CONF_LISTVIEW_S_ASCEND,   g_fSortAscend);\r
91         }\r
92 \r
93         this->Close(true);\r
94 }\r
95 \r
96 //******************************************************************************\r
97 // Event Table.\r
98 //******************************************************************************\r
99 \r
100 BEGIN_EVENT_TABLE(MainFrame, wxFrame)\r
101         EVT_INIT_DIALOG(      MainFrame::OnInit)\r
102         // Menu\r
103         EVT_MENU(XRCID("Arc_Create"),  MainFrame::OnArcCreate)\r
104         EVT_MENU(XRCID("Arc_Open"),    MainFrame::OnArcOpen)\r
105         EVT_MENU(XRCID("Arc_Close"),   MainFrame::OnArcClose)\r
106         EVT_MENU(XRCID("Arc_Clone"),   MainFrame::OnArcClone)\r
107         EVT_MENU(XRCID("Arc_Add"),     MainFrame::OnArcAdd)\r
108         EVT_MENU(XRCID("Arc_SFX"),     MainFrame::OnArcConvert)\r
109         EVT_MENU(XRCID("Arc_UnSFX"),   MainFrame::OnArcConvert)\r
110         EVT_MENU(XRCID("Exe_Exit"),    MainFrame::OnExit)\r
111         EVT_MENU(XRCID("Arc_Extract"), MainFrame::OnArcExtract)\r
112         EVT_MENU(XRCID("Arc_Delete"),  MainFrame::OnArcDelete)\r
113         EVT_MENU(XRCID("Arc_Test"),    MainFrame::OnArcTest)\r
114         EVT_MENU(XRCID("Arc_Repair"),  MainFrame::OnArcRepair)\r
115         EVT_MENU(XRCID("Exe_Copy"),    MainFrame::OnExeCopy)\r
116         EVT_MENU(XRCID("Exe_View_Icons"),  MainFrame::OnViewMode)\r
117         EVT_MENU(XRCID("Exe_View_Details"),MainFrame::OnViewMode)\r
118         EVT_MENU(XRCID("Exe_View_List"),   MainFrame::OnViewMode)\r
119         EVT_MENU(XRCID("Exe_View_ToolBar"),MainFrame::OnShowToolBar)\r
120         EVT_MENU(XRCID("Exe_View_StatusBar"),MainFrame::OnShowStatusBar)\r
121         EVT_MENU(XRCID("Exe_View_SelectAll"),MainFrame::OnSelectAll)\r
122         // TreeView\r
123         EVT_TREE_SEL_CHANGED(XRCID("TreeView"), MainFrame::OnTreeChanged)\r
124         EVT_TREE_BEGIN_DRAG( XRCID("TreeView"), MainFrame::OnTreeBeginDrag)\r
125         EVT_COMMAND_CONTEXT_MENU(XRCID("TreeView"), MainFrame::OnContextMenu)\r
126         // ListView\r
127         EVT_LIST_ITEM_SELECTED(  XRCID("ListView"), MainFrame::OnListItemSelect)\r
128         EVT_LIST_ITEM_DESELECTED(XRCID("ListView"), MainFrame::OnListItemSelect)\r
129         EVT_LIST_ITEM_ACTIVATED( XRCID("ListView"), MainFrame::OnListItemDClick)\r
130         EVT_LIST_BEGIN_DRAG(     XRCID("ListView"), MainFrame::OnListBeginDrag)\r
131         EVT_COMMAND_CONTEXT_MENU(XRCID("ListView"), MainFrame::OnContextMenu)\r
132         // Filter\r
133         EVT_TEXT(XRCID("tcFilter"), MainFrame::OnFilter)\r
134 END_EVENT_TABLE()\r
135 \r
136 //******************************************************************************\r
137 // Event handler.\r
138 //******************************************************************************\r
139 \r
140 void MainFrame::OnInit(wxInitDialogEvent&)\r
141 {\r
142         // XRCと結びつけ。\r
143         this->menubar    = this->GetMenuBar();\r
144         this->toolbar    = this->GetToolBar();\r
145         this->statusbar = XRCCTRL(* this, "statusbar", wxStatusBar);\r
146         this->tree_ctrl = XRCCTRL(* this, "TreeView", wxTreeCtrl);\r
147         this->list_ctrl = XRCCTRL(* this, "ListView", myListCtrl);\r
148         this->window_splitter = XRCCTRL(* this, "window_splitter", wxSplitterWindow);\r
149         this->tcFilter  = XRCCTRL(* this->toolbar, "tcFilter", wxTextCtrl);\r
150 \r
151         // 設定を読み込み。\r
152         this->SetSize(this->conf.ReadId(CONF_WINDOW_X, 0l), this->conf.ReadId(CONF_WINDOW_Y, 0l), this->conf.ReadId(CONF_WINDOW_WIDTH, 800l), this->conf.ReadId(CONF_WINDOW_HEIGHT, 400l), wxSIZE_ALLOW_MINUS_ONE);\r
153         wxTheMimeTypesManager->Initialize(wxMAILCAP_ALL);\r
154 \r
155         // 初期値設定。\r
156         {\r
157                 wxIcon icon;\r
158                 icon.CopyFromBitmap(wxBitmap(L_DIR_S_ICO wxT("app.png"), wxBITMAP_TYPE_ANY));\r
159                 this->SetIcon(icon);\r
160         }\r
161         wxCommandEvent e;\r
162         this->OnArcClose(e);\r
163         this->SetDropTarget(new myFileDropTarget(this));\r
164 \r
165         // スプリッター設定。\r
166         this->window_splitter->SetSashPosition(this->conf.ReadId(CONF_WINDOW_SPLITTER_POS, 200l));\r
167 \r
168         // リストビュー設定。\r
169         int nIconMode = this->conf.ReadId(CONF_LISTVIEW_SHOWMODE, 0l);\r
170         e.SetId(nIconMode == 1 ? XRCID("Exe_View_Icons") : (nIconMode == 2 ? XRCID("Exe_View_List") : XRCID("Exe_View_Details")));\r
171         this->OnViewMode(e);\r
172         // wxGTKでは直接wxLC_VIRTUALを指定しないと反映されない。\r
173         this->list_ctrl->SetSingleStyle(wxLC_VIRTUAL);\r
174         this->list_ctrl->InsertColumn(0, _("Filename"),      wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_FILENAME, 140l));\r
175         this->list_ctrl->InsertColumn(1, _("Unpacked"),      wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_UNPACKED,  80l));\r
176         this->list_ctrl->InsertColumn(2, _("Packed"),        wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_PACKED,    80l));\r
177         this->list_ctrl->InsertColumn(3, _("Ratio"),         wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_RATIO,     50l));\r
178         this->list_ctrl->InsertColumn(4, _("Method"),        wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_METHOD,    60l));\r
179         this->list_ctrl->InsertColumn(5, _("Attr"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_ATTR,      50l));\r
180         this->list_ctrl->InsertColumn(6, _("Last modified"), wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_LASTMOD,  150l));\r
181         this->list_ctrl->InsertColumn(7, _("Path"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_PATH,     100l));\r
182         this->list_ctrl->InsertColumn(8, _("Type"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_TYPE,     100l));\r
183         this->list_ctrl->InsertColumn(9, _("No."),           wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_NO,        35l));\r
184         this->list_ctrl->InsertColumn(10,_("Comment"),       wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_COMMENT,   35l));\r
185         g_nSortColumn = this->conf.ReadId(CONF_LISTVIEW_S_COLUMN, 9l);\r
186         g_fSortAscend = this->conf.ReadId(CONF_LISTVIEW_S_ASCEND, true);\r
187 \r
188         // ツールバー/ステータスバー設定。\r
189         int nStatusBarParts[] = {70, 70, 180, 50, -1};\r
190         this->statusbar->SetFieldsCount(5, nStatusBarParts);\r
191         this->SetStatusBarPane(-1);\r
192         bool fShow = this->conf.ReadId(CONF_WINDOW_STATUSBAR, true);\r
193         this->menubar->Check(XRCID("Exe_View_StatusBar"), fShow);\r
194         this->statusbar->Show(fShow);\r
195         fShow = this->conf.ReadId(CONF_WINDOW_TOOLBAR, true);\r
196         this->menubar->Check(XRCID("Exe_View_ToolBar"), fShow);\r
197         this->toolbar->Show(fShow);\r
198 }\r
199 \r
200 // MenuBar\r
201 \r
202 void MainFrame::OnExit(wxCommandEvent&)\r
203 {\r
204         this->Close(true);\r
205 }\r
206 \r
207 void MainFrame::OnArcCreate(wxCommandEvent& e)\r
208 {\r
209         TPI_SWITCHES swInfo;\r
210         swInfo.pCustomSwitches = NULL;\r
211 \r
212         // 作成ダイアログを設定。\r
213         MakeDialog mkDlg;\r
214         mkDlg.SetParent(this);\r
215         if (e.GetClientData() == NULL)\r
216         {\r
217                 // 処理対象のファイルを選択。\r
218                 wxFileDialog fd(this, _("Choose files to compress"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\r
219                 if (fd.ShowModal() == wxID_CANCEL)\r
220                 {\r
221                         return;\r
222                 }\r
223                 swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
224                 this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
225                 fd.GetFilenames(mkDlg.files);\r
226         }\r
227         else\r
228         {\r
229                 mkDlg.files = * (wxArrayString *) e.GetClientData();\r
230                 swInfo.fnDestinationDirectory = wxFileName::DirName(wxFileName(mkDlg.files[0]).GetPath());\r
231                 // 相対パスに変換。\r
232                 for (size_t n = 0; n < mkDlg.files.GetCount(); n++)\r
233                 {\r
234                         wxFileName fn(mkDlg.files[n]);\r
235                         fn.MakeRelativeTo(swInfo.fnDestinationDirectory.GetPath());\r
236                         mkDlg.files[n] = fn.GetFullPath();\r
237                 }\r
238         }\r
239 \r
240         this->OnArcClose(e);\r
241         // 書庫名はファイル名の拡張子より前、もしくはディレクトリ名。\r
242         this->fnArchive = wxFileName(mkDlg.files[0]);\r
243         this->fnArchive.SetName(mkDlg.files.GetCount() == 1 ? (this->fnArchive.GetName().IsEmpty() ? this->fnArchive.GetDirs().Last() : this->fnArchive.GetName()) : swInfo.fnDestinationDirectory.GetDirs().Last());\r
244         this->fnArchive.SetEmptyExt();\r
245         this->fnArchive.SetPath(swInfo.fnDestinationDirectory.GetPath());\r
246 \r
247         // ダイアログを表示。\r
248         if (mkDlg.ShowModal() == wxID_CANCEL)\r
249         {\r
250                 return;\r
251         }\r
252 \r
253         // 各種設定。\r
254         int nSelected = mkDlg.chType->GetSelection();\r
255         swInfo.nArchiveType         = mkDlg.afInfo[nSelected].nTypeId;\r
256         swInfo.fStoreDirectoryPathes= ! mkDlg.cbIgnorePath->IsChecked();\r
257         swInfo.fMakeSFX                     = mkDlg.cbMakeSFX->IsChecked();\r
258         swInfo.fSolid               = mkDlg.cbSolid->IsChecked();\r
259         swInfo.fMMOptimize          = mkDlg.cbMMOptimize->IsChecked();\r
260         swInfo.fEncryptHeader       = mkDlg.cbEncryptHeader->IsChecked();\r
261         swInfo.fCompressHeader      = mkDlg.cbCompressHeader->IsChecked();\r
262         swInfo.nCompressLevel       = mkDlg.scLevel->GetValue();\r
263         swInfo.nRecoveryRecord      = mkDlg.scRR->GetValue();\r
264         swInfo.szPassword           = mkDlg.tcPassword->GetValue();\r
265         swInfo.szKeyFile            = mkDlg.tcKeyfile->GetValue();\r
266         swInfo.szComment            = mkDlg.tcComment->GetValue();\r
267         mkDlg.cbSplitSize->GetValue().ToULongLong(& swInfo.nSplitSize);\r
268 \r
269         // TPIを読み込み。\r
270         this->fnArchive = wxFileName(mkDlg.cbDir->GetValue(), mkDlg.cbFileName->GetValue());\r
271         if (! tpi.InitLibrary(mkDlg.afInfo[nSelected].szTPIName, this->fnArchive.GetFullPath(), TPICallbackProc, mkDlg.afInfo[nSelected].nTypeId))\r
272         {\r
273                 this->ErrorCheck(tpi.nErrorCode, wxT("InitLibrary"));\r
274                 return;\r
275         }\r
276 \r
277         // 処理を行う。\r
278         {\r
279                 ProcessDialog procDlg;\r
280                 procDlg.fnArchive  = & this->fnArchive;\r
281                 procDlg.nFileCount = mkDlg.files.GetCount();\r
282                 procDlg.Show(true);\r
283 \r
284                 tpi.Command(TPI_COMMAND_CREATE, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
285                 this->ErrorCheck(tpi.nErrorCode);\r
286                 procDlg.Show(false);\r
287         }\r
288         tpi.FreeLibrary();\r
289 \r
290         if (mkDlg.cbOpenAfter->IsChecked())\r
291         {\r
292                 // 作成先を開く。\r
293                 ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
294         }\r
295 \r
296         if (mkDlg.cbExitAfter->IsChecked())\r
297         {\r
298                 // 終了。\r
299                 this->Close(true);\r
300         }\r
301 \r
302         // 終了しない場合は書庫を開く。\r
303         this->OnArcOpen(e);\r
304 }\r
305 \r
306 void MainFrame::OnArcOpen(wxCommandEvent& e)\r
307 {\r
308         // モード取得。通常は0, それ以外で開く場合は1, ファイルDnDなら2。\r
309         int nMode = e.GetInt() == 2 ? 2 : e.GetId() == XRCID("Arc_Open") ? 0 : 1;\r
310 \r
311         // 書庫を選択。\r
312         if (nMode == 0)\r
313         {\r
314                 wxFileDialog fd(this, _("Choose an archive"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST);\r
315                 if (fd.ShowModal() == wxID_CANCEL)\r
316                 {\r
317                         return;\r
318                 }\r
319                 this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
320                 this->fnArchive = wxFileName(fd.GetPath());\r
321         }\r
322 \r
323         // 進捗ダイアログ表示。\r
324         ProcessDialog procDlg;\r
325         procDlg.fnArchive  = & this->fnArchive;\r
326         procDlg.Show(true);\r
327 \r
328         // DnD以外で書庫を開く場合、TPIを読み込み。\r
329         TPI_PROCESSINFO piInfo;\r
330         if (! this->LoadTPI(this->fnArchive.GetFullPath(), & piInfo.fiInfo.nUnpackedSize))\r
331         {\r
332                 procDlg.Show(false);\r
333                 if (nMode == 2)\r
334                 {\r
335                         // DnDの場合は書庫を作成する。\r
336                         this->OnArcCreate(e);\r
337                 }\r
338                 else if (this->IsShown())\r
339                 {\r
340                         wxBell();\r
341                         this->statusbar->SetStatusText(_("No plug-in supporting this archive was found!"), 4);\r
342                 }\r
343                 else\r
344                 {\r
345                         wxLogError(_("No plug-in supporting this archive was found!"));\r
346                         this->Close(true);\r
347                 }\r
348                 return;\r
349         }\r
350 \r
351         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
352         piInfo.eStatus = 0x1001;\r
353         if (this->ErrorCheck(procDlg.CallbackProc(TPI_NOTIFY_COMMON, & piInfo), wxT("Callback")) == TPI_CALLBACK_CANCEL)\r
354         {\r
355                 procDlg.Show(false);\r
356                 tpi.CloseArchive();\r
357                 wxCommandEvent e;\r
358                 this->OnArcClose(e);\r
359                 return;\r
360         }\r
361 \r
362         // 配列のサイズを確保。\r
363         this->fileinfo.Alloc(piInfo.fiInfo.nUnpackedSize);\r
364 \r
365         // 履歴に追加。\r
366         this->conf.WriteHistory(CONF_HISTORY_PATH, this->fnArchive.GetPath());\r
367         this->conf.WriteHistory(CONF_HISTORY_NAME, this->fnArchive.GetFullName());\r
368         this->conf.WriteHistory(CONF_HISTORY_FULL, this->fnArchive.GetFullPath());\r
369 \r
370         // 書庫のアイコンを取得し、書庫ルートを作成。\r
371         g_hIconT.Add(wxBitmap(L_DIR_S_ICO wxT("folder_closed.png"), wxBITMAP_TYPE_ANY));\r
372         g_hIconT.Add(wxBitmap(L_DIR_S_ICO wxT("folder_open.png"), wxBITMAP_TYPE_ANY));\r
373         this->tree_ctrl->SetImageList(& g_hIconT);\r
374         wxTreeItemId\r
375                 idRoot = this->tree_ctrl->AddRoot(wxEmptyString),\r
376 #ifdef __WINDOWS__\r
377                 idArchive = this->tree_ctrl->AppendItem(idRoot, this->fnArchive.GetFullName(), g_hIconT.Add(GetFileTypeIcon(piInfo.fiInfo.fnFileName))),\r
378 #else\r
379                 idArchive = this->tree_ctrl->AppendItem(idRoot, this->fnArchive.GetFullName(), g_hIconT.Add(GetFileTypeIcon(piInfo.fiInfo.fnFileName).ConvertToImage().Rescale(16, 16))),\r
380 #endif\r
381                 idArcRoot = this->tree_ctrl->AppendItem(idRoot, wxT("-----"), 0, 1);\r
382 \r
383         // ファイル情報をロード。\r
384         if (tpi.GetFileInformation(& piInfo.fiInfo, true))\r
385         {\r
386                 piInfo.eStatus = 0x1002;\r
387                 piInfo.nProcessedSize = 0;\r
388                 do\r
389                 {\r
390                         piInfo.nProcessedSize++;\r
391                         if (this->ErrorCheck(procDlg.CallbackProc(TPI_NOTIFY_COMMON, & piInfo), wxT("Callback")) == TPI_CALLBACK_CANCEL)\r
392                         {\r
393                                 procDlg.Show(false);\r
394                                 tpi.CloseArchive();\r
395                                 wxCommandEvent e;\r
396                                 this->OnArcClose(e);\r
397                                 return;\r
398                         }\r
399 \r
400                         // 拡張子のみ設定されている場合。\r
401                         if (piInfo.fiInfo.szStoredName.IsEmpty())\r
402                         {\r
403                                 piInfo.fiInfo.szStoredName = this->fnArchive.GetName();\r
404                                 if (piInfo.fiInfo.fnFileName.HasExt())\r
405                                 {\r
406                                         piInfo.fiInfo.szStoredName += wxT('.') + piInfo.fiInfo.fnFileName.GetExt();\r
407                                 }\r
408                                 piInfo.fiInfo.fnFileName = wxFileName(piInfo.fiInfo.szStoredName);\r
409                         }\r
410 \r
411                         // セキュリティチェック。\r
412                         // ルート記号を削除。\r
413                         wxString szPath = piInfo.fiInfo.fnFileName.GetPathWithSep(wxPATH_UNIX);\r
414                         if (szPath.StartsWith(wxT("/")) || szPath.StartsWith(wxT("./")))\r
415                         {\r
416                                 piInfo.fiInfo.fnFileName = wxFileName(szPath.AfterFirst(wxT('/')), piInfo.fiInfo.fnFileName.GetFullName(), wxPATH_DOS);\r
417                         }\r
418                         // ルートメンバの情報は無視する。\r
419                         if (piInfo.fiInfo.fnFileName.GetFullPath().IsEmpty() || piInfo.fiInfo.fnFileName.GetFullPath() == wxT("."))\r
420                         {\r
421                                 continue;\r
422                         }\r
423 \r
424                         // 改行文字/タブ文字などを削除。\r
425                         if (piInfo.fiInfo.szStoredName.Find(wxT('\r')) != wxNOT_FOUND\r
426                         ||  piInfo.fiInfo.szStoredName.Find(wxT('\n')) != wxNOT_FOUND\r
427                         ||  piInfo.fiInfo.szStoredName.Find(wxT('\t')) != wxNOT_FOUND)\r
428                         {\r
429                                 wxString sz = piInfo.fiInfo.fnFileName.GetFullPath();\r
430                                 sz.Replace(wxT("\r"), wxT(" "));\r
431                                 sz.Replace(wxT("\n"), wxT(" "));\r
432                                 sz.Replace(wxT("\t"), wxT(" "));\r
433                                 piInfo.fiInfo.eDanger = TRUE;\r
434                                 piInfo.fiInfo.fnFileName = wxFileName(sz);\r
435                                 wxLogWarning(_("This archive may contain files whose name contains some special characters like CR(\\r), LF(\\n), Tab(\\t) and some problem would be happen if you extract these files. Don\'t extract these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
436                         }\r
437 \r
438                         // DTV検査。\r
439                         if (piInfo.fiInfo.fnFileName.GetPathWithSep(wxPATH_UNIX).Find(wxT("../")) != wxNOT_FOUND)\r
440                         {\r
441                                 piInfo.fiInfo.eDanger = TRUE;\r
442                                 wxLogWarning(_("This archive may have Directory Traversal Vulnerability(DTV) problem, and some danger files may be extracted to the unexpected system directory! You should use the \"Ignore file pathes\" option when extracting this archive.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
443                         }\r
444                         // 空白の連続による拡張子偽装を検査。\r
445                         if (piInfo.fiInfo.fnFileName.GetFullName().Find(wxT("        ")) != wxNOT_FOUND)\r
446                         {\r
447                                 piInfo.fiInfo.eDanger = TRUE;\r
448                                 wxLogWarning(_("This archive may contain extension-disguised files whose real extension is hidden by using many blank charactor and you may mistake that it is a \"safe\" file. Don\'t execute these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
449                         }\r
450                         // Unicode制御文字を検査。\r
451                         for (wxChar c = 0x200c; c <= 0x206f; c++)\r
452                         {\r
453                                 if (piInfo.fiInfo.fnFileName.GetFullName().Find(c) != wxNOT_FOUND)\r
454                                 {\r
455                                         piInfo.fiInfo.eDanger = TRUE;\r
456                                         wxLogWarning(_("This archive may contain extension-disguised files whose real extension is hidden by using Unicode control character and you may mistake that it is a \"safe\" file. Don\'t execute these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
457                                 }\r
458                                 switch (c)\r
459                                 {\r
460                                 case 0x200f: c = 0x2027; break;\r
461                                 case 0x202e: c = 0x2060; break;\r
462                                 }\r
463                         }\r
464 \r
465                         // ツリービューに反映。\r
466                         bool fDir = piInfo.fiInfo.dwAttribute & TPI_ATTRIBUTE_DIRECTORY ? true : false;\r
467                         TreeView_CheckNewerItem(this->tree_ctrl, idArcRoot, fDir ? piInfo.fiInfo.fnFileName.GetFullPath() : piInfo.fiInfo.fnFileName.GetPath(), true);\r
468 \r
469                         // ディレクトリ属性を含むものについては情報を保存しない。\r
470                         if (fDir)\r
471                         {\r
472                                 continue;\r
473                         }\r
474 \r
475                         // 情報を保存してカウントアップ。\r
476                         this->fileinfo.Add(piInfo.fiInfo);\r
477                 }\r
478                 while (tpi.GetFileInformation(& piInfo.fiInfo));\r
479         }\r
480 \r
481         // GetFileInformationがエラー終了した場合。\r
482         this->ErrorCheck(tpi.nErrorCode, wxT("GetFileInformation"));\r
483 \r
484         // 書庫の情報を取得。\r
485         tpi.GetArchiveInformation(& this->aiArchive);\r
486         this->ErrorCheck(tpi.nErrorCode, wxT("GetArchiveInformation"));\r
487 \r
488         // 書庫を閉じる。\r
489         tpi.CloseArchive();\r
490         this->ErrorCheck(tpi.nErrorCode, wxT("CloseArchive"));\r
491 \r
492         // 以下、UI処理。\r
493         this->fileinfo.Shrink();\r
494         this->tree_ctrl->Freeze();\r
495         this->tree_ctrl->ExpandAll();\r
496         this->tree_ctrl->ScrollTo(idArchive);\r
497         this->tree_ctrl->SelectItem(idArchive);\r
498         this->tree_ctrl->SetScrollPos(wxHORIZONTAL, 0);\r
499         this->tree_ctrl->Thaw();\r
500         this->list_ctrl->atDangerItem.SetTextColour(* wxRED);\r
501         this->list_ctrl->atEncryptedItem.SetTextColour(wxColour(wxT("forest green")));\r
502 \r
503         // ステータスバー設定。\r
504         this->statusbar->SetStatusText(this->aiArchive.fiInfo.szTypeName, 0);\r
505         this->statusbar->SetStatusText(wxString::Format(_("%u file(s)"), this->fileinfo.GetCount()), 1);\r
506         this->statusbar->SetStatusText(wxString::Format(wxString("%" wxLongLongFmtSpec "uB -> %" wxLongLongFmtSpec "uB"), this->aiArchive.nUnpackedSize, this->aiArchive.nPackedSize), 2);\r
507         this->statusbar->SetStatusText(wxString::Format(wxT("%3.1f%%"), this->aiArchive.wCompressRatio / 10.0), 3);\r
508         this->statusbar->SetStatusText(this->fnArchive.GetFullPath(), 4);\r
509         this->statusbar->SetToolTip(\r
510                 wxString::Format(\r
511                         _("%s(%s)\nModify: %s\nCreate: %s\nTPI: %s(%s)"),\r
512                         this->fnArchive.GetFullName().c_str(), this->aiArchive.fiInfo.szTypeName.c_str(),\r
513                         this->aiArchive.tmModify.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
514                         this->aiArchive.tmCreate.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
515                         this->aiArchive.fiInfo.szTPIName.c_str(), this->aiArchive.fiInfo.szEngineName.c_str()\r
516                 )\r
517         );\r
518 \r
519         // ツールバー・メニューバー設定。ファイル選択時しか動作しない削除などは別に設定。\r
520         SetMenuToolState("Arc_Close",   true);\r
521         SetMenuToolState("Arc_Add",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_ADD)   == TPI_COMMAND_ADD   && this->aiArchive.fiInfo.fArchive);\r
522         SetMenuToolState("Arc_SFX",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_SFX)    == TPI_COMMAND_SFX   && ! this->aiArchive.fSFX);\r
523         SetMenuToolState("Arc_UnSFX",   (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_UNSFX)  == TPI_COMMAND_UNSFX && this->aiArchive.fSFX);\r
524         SetMenuToolState("Arc_Extract", (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_EXTRACT)== TPI_COMMAND_EXTRACT);\r
525         SetMenuToolState("Arc_Test",    (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_TEST)   == TPI_COMMAND_TEST);\r
526         SetMenuToolState("Arc_Repair",  (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_REPAIR) == TPI_COMMAND_REPAIR);\r
527         this->menubar->Enable(XRCID("Arc_Clone"), true);\r
528 \r
529         procDlg.Show(false);\r
530         this->Raise();\r
531 }\r
532 \r
533 void MainFrame::OnArcClose(wxCommandEvent& e)\r
534 {\r
535         // ツリービュー・リストビュー設定。\r
536         this->tree_ctrl->DeleteAllItems();\r
537         this->list_ctrl->DeleteAllItems();\r
538         this->list_ctrl->apShowFile.Clear();\r
539 \r
540         // ツールバー・メニューバー設定。\r
541         SetMenuToolState("Arc_Close",   false);\r
542         SetMenuToolState("Arc_Add",     false);\r
543         SetMenuToolState("Arc_SFX",     false);\r
544         SetMenuToolState("Arc_UnSFX",   false);\r
545         SetMenuToolState("Arc_Extract", false);\r
546         SetMenuToolState("Arc_Delete",  false);\r
547         SetMenuToolState("Arc_Test",    false);\r
548         SetMenuToolState("Arc_Repair",  false);\r
549         this->menubar->Enable(XRCID("Arc_Clone"), false);\r
550 \r
551         for (int i = 0; i < this->statusbar->GetFieldsCount(); i++)\r
552         {\r
553                 this->statusbar->SetStatusText(wxEmptyString, i);\r
554         }\r
555         this->statusbar->SetToolTip(wxEmptyString);\r
556         this->fileinfo.Clear();\r
557         this->aiArchive.szComment.Empty();\r
558         this->aiArchive.fnArchive.Clear();\r
559         this->aiArchive.fiInfo.szTypeName.Empty();\r
560         this->aiArchive.fiInfo.szSuffix.Empty();\r
561         this->aiArchive.fiInfo.szEngineName.Empty();\r
562         this->aiArchive.fiInfo.szTPIName.Empty();\r
563 \r
564         g_hIconT.RemoveAll();\r
565         g_hIconLL.RemoveAll();\r
566         g_hIconLS.RemoveAll();\r
567 \r
568         // DnDで書庫を開くときは既に読み込まれているTPIを用いるので、解放してはいけない。\r
569         if (e.GetExtraLong() == 0)\r
570         {\r
571                 tpi.FreeLibrary();\r
572         }\r
573 }\r
574 \r
575 void MainFrame::OnArcClone(wxCommandEvent&)\r
576 {\r
577         // 保存先を尋ねる。\r
578         wxFileDialog fd(this, _("Clone archive"), this->fnArchive.GetPath(), this->fnArchive.GetFullName(), wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\r
579         if (fd.ShowModal() == wxID_CANCEL)\r
580         {\r
581                 return;\r
582         }\r
583         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
584 \r
585         // コピー。\r
586         ::wxCopyFile(this->fnArchive.GetFullPath(), fd.GetPath());\r
587         wxFileName fn(fd.GetPath());\r
588         wxDateTime dtAccess, dtModify, dtCreate;\r
589         this->fnArchive.GetTimes(& dtAccess, & dtModify, & dtCreate);\r
590         fn.SetTimes(& dtAccess, & dtModify, & dtCreate);\r
591 }\r
592 \r
593 void MainFrame::OnArcAdd(wxCommandEvent& e)\r
594 {\r
595         // 作成ダイアログを設定。\r
596         MakeDialog mkDlg;\r
597         mkDlg.SetParent(this);\r
598         mkDlg.uCommand = TPI_COMMAND_ADD;\r
599 \r
600         TPI_SWITCHES swInfo;\r
601         swInfo.pCustomSwitches       = NULL;\r
602 \r
603         if (e.GetClientData() == NULL)\r
604         {\r
605                 if (::wxGetKeyState(WXK_SHIFT))\r
606                 {\r
607                         // 処理対象のフォルダを選択。\r
608                         wxDirDialog dd(this, _("Choose dir to add"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxDD_DIR_MUST_EXIST);\r
609                         if (dd.ShowModal() == wxID_CANCEL)\r
610                         {\r
611                                 return;\r
612                         }\r
613                         swInfo.fnDestinationDirectory = wxFileName(dd.GetPath());\r
614                         this->conf.WriteHistory(CONF_HISTORY_PATH, swInfo.fnDestinationDirectory.GetPath());\r
615                         mkDlg.files.Add(swInfo.fnDestinationDirectory.GetFullName());\r
616                 }\r
617                 else\r
618                 {\r
619                         // 処理対象のファイルを選択。\r
620                         wxFileDialog fd(this, _("Choose files to add"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\r
621                         if (fd.ShowModal() == wxID_CANCEL)\r
622                         {\r
623                                 return;\r
624                         }\r
625                         fd.GetFilenames(mkDlg.files);\r
626                         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
627                         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
628                 }\r
629         }\r
630         else\r
631         {\r
632                 mkDlg.files = * (wxArrayString *) e.GetClientData();\r
633                 swInfo.fnDestinationDirectory = wxFileName::DirName(wxFileName(mkDlg.files[0]).GetPath());\r
634                 // 相対パスに変換。\r
635                 for (size_t n = 0; n < mkDlg.files.GetCount(); n++)\r
636                 {\r
637                         wxFileName fn(mkDlg.files[n]);\r
638                         fn.MakeRelativeTo(swInfo.fnDestinationDirectory.GetPath());\r
639                         mkDlg.files[n] = fn.GetFullPath();\r
640                 }\r
641         }\r
642 \r
643         // ダイアログを表示。\r
644         if (mkDlg.ShowModal() == wxID_CANCEL)\r
645         {\r
646                 return;\r
647         }\r
648 \r
649         // 各種設定。\r
650         swInfo.fMakeSFX              = false;\r
651         swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
652         swInfo.fSolid               = mkDlg.cbSolid->IsChecked();\r
653         swInfo.fMMOptimize          = mkDlg.cbMMOptimize->IsChecked();\r
654         swInfo.fEncryptHeader       = mkDlg.cbEncryptHeader->IsChecked();\r
655         swInfo.nCompressLevel       = mkDlg.scLevel->GetValue();\r
656         swInfo.nRecoveryRecord      = mkDlg.scRR->GetValue();\r
657         swInfo.szPassword           = mkDlg.tcPassword->GetValue();\r
658         swInfo.szKeyFile            = mkDlg.tcKeyfile->GetValue();\r
659         swInfo.szComment            = mkDlg.tcComment->GetValue();\r
660 \r
661         // 処理を行う。\r
662         {\r
663                 ProcessDialog procDlg;\r
664                 procDlg.fnArchive  = & this->fnArchive;\r
665                 procDlg.nFileCount = mkDlg.files.GetCount();\r
666                 procDlg.Show(true);\r
667 \r
668                 tpi.Command(TPI_COMMAND_ADD, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
669                 this->ErrorCheck(tpi.nErrorCode);\r
670                 procDlg.Show(false);\r
671         }\r
672 \r
673         if (mkDlg.cbOpenAfter->IsChecked())\r
674         {\r
675                 // 作成先を開く。\r
676                 ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
677         }\r
678 \r
679         if (mkDlg.cbExitAfter->IsChecked())\r
680         {\r
681                 // 終了。\r
682                 this->Close(true);\r
683         }\r
684 \r
685         // 終了しない場合は書庫を再読み込み。\r
686         this->OnArcOpen(e);\r
687 }\r
688 \r
689 void MainFrame::OnArcConvert(wxCommandEvent& e)\r
690 {\r
691         TPI_SWITCHES swInfo;\r
692         swInfo.fMakeSFX = e.GetId() == XRCID("Arc_SFX");\r
693 \r
694         // 保存先を尋ねる。\r
695         wxFileDialog fd(this, swInfo.fMakeSFX ? _("Save as SFX") : _("Save as normal archive"), this->fnArchive.GetPath(), this->fnArchive.GetName() + (swInfo.fMakeSFX ? EXE_EXT : (wxString) wxEmptyString), wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\r
696         if (fd.ShowModal() == wxID_CANCEL)\r
697         {\r
698                 return;\r
699         }\r
700         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
701         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
702 \r
703         wxArrayString files;\r
704         files.Add(fd.GetPath());\r
705 \r
706         ProcessDialog procDlg;\r
707         procDlg.Show(true);\r
708         tpi.Command(swInfo.fMakeSFX ? TPI_COMMAND_SFX : TPI_COMMAND_UNSFX, & swInfo, this->fnArchive.GetFullPath(), files);\r
709         this->ErrorCheck(tpi.nErrorCode);\r
710         procDlg.Show(false);\r
711 }\r
712 \r
713 void MainFrame::OnArcExtract(wxCommandEvent& e)\r
714 {\r
715         TPI_SWITCHES swInfo;\r
716         swInfo.pCustomSwitches = NULL;\r
717 \r
718         // モード取得。通常は0, 実行なら1, ファイルDnDなら2、ディレクトリDnDなら3、クリップボードなら4、コンテキストメニューからなら8。\r
719         int nMode = e.GetInt();\r
720         if (e.GetInt() == 8)\r
721         {\r
722                 nMode = 0;\r
723         }\r
724         // 実行時のみ使用。\r
725         wxFileType * ftFile = NULL;\r
726 \r
727         // 展開ダイアログを作成。DnDまたは実行時は表示しない。\r
728         MakeDialog mkDlg;\r
729         mkDlg.SetParent(this);\r
730         mkDlg.uCommand = TPI_COMMAND_EXTRACT;\r
731         mkDlg.files    = MakeTargetFileList(this, nMode == 1, nMode == 0);\r
732 \r
733         bool bMakeDir = false;\r
734         if (nMode != 0)\r
735         {\r
736                 // 作業ディレクトリ作成。\r
737                 swInfo.fStoreDirectoryPathes = false;\r
738                 wxString szDestDirBase = nMode == 3 ? this->tree_ctrl->GetItemText(this->tree_ctrl->GetSelection()) : wxT("tpi_tmp");\r
739                 wxStandardPaths p;\r
740                 if (szDestDirBase == wxT("-----"))\r
741                 {\r
742                         // 書庫ルートのときは書庫名にしておく。\r
743                         szDestDirBase = this->fnArchive.GetName();\r
744                 }\r
745                 swInfo.fnDestinationDirectory = MakeDirPath(wxFileName::DirName(p.GetTempDir()), szDestDirBase, true);\r
746                 if (! swInfo.fnDestinationDirectory.IsOk())\r
747                 {\r
748                         wxLogError(_("Unable to make the temporary directory!"));\r
749                         return;\r
750                 }\r
751         }\r
752         else\r
753         {\r
754                 if (mkDlg.ShowModal() == wxID_CANCEL)\r
755                 {\r
756                         return;\r
757                 }\r
758 \r
759                 // 各種設定。\r
760                 swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
761                 swInfo.fnDestinationDirectory = wxFileName::DirName(mkDlg.cbDir->GetValue());\r
762                 swInfo.szPassword = mkDlg.tcPassword->GetValue();\r
763                 swInfo.szKeyFile  = mkDlg.tcKeyfile->GetValue();\r
764 \r
765                 // 必要なら書庫名でディレクトリを作成する。\r
766                 bMakeDir = WillMakeDirByArcName(this, & mkDlg);\r
767                 if (bMakeDir)\r
768                 {\r
769                         swInfo.fnDestinationDirectory = MakeDirPath(swInfo.fnDestinationDirectory, this->fnArchive.GetName(), true);\r
770                         if (! swInfo.fnDestinationDirectory.IsOk())\r
771                         {\r
772                                 wxLogError(_("Unable to make the destination directory!"));\r
773                                 return;\r
774                         }\r
775                 }\r
776         }\r
777 \r
778         // 処理を行う。\r
779         {\r
780                 ProcessDialog procDlg;\r
781                 procDlg.fnArchive  = & this->fnArchive;\r
782                 procDlg.nFileCount = mkDlg.files.GetCount();\r
783                 procDlg.Show(true);\r
784 \r
785                 tpi.Command(TPI_COMMAND_EXTRACT, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
786                 this->ErrorCheck(tpi.nErrorCode);\r
787                 procDlg.Show(false);\r
788         }\r
789 \r
790         if (nMode == 0)\r
791         {\r
792                 if (mkDlg.cbOpenAfter->IsChecked())\r
793                 {\r
794                         // 展開先を開く。\r
795                         if (mkDlg.chDirMake->GetSelection() == 2 && ! bMakeDir)\r
796                         {\r
797                                 wxTreeItemId tiArcSub = this->tree_ctrl->GetLastChild(this->tree_ctrl->GetLastChild(this->tree_ctrl->GetRootItem()));\r
798                                 if (tiArcSub.IsOk())\r
799                                 {\r
800                                         swInfo.fnDestinationDirectory.SetFullName(this->tree_ctrl->GetItemText(tiArcSub));\r
801                                 }\r
802                         }\r
803                         ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
804                 }\r
805 \r
806                 if (mkDlg.cbExitAfter->IsChecked())\r
807                 {\r
808                         // 終了。\r
809                         this->Close(true);\r
810                 }\r
811         }\r
812         else\r
813         {\r
814                 if (nMode == 1)\r
815                 {\r
816                         // コマンドを取得。\r
817                         ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(wxFileName(mkDlg.files[0], wxPATH_DOS).GetExt());\r
818                         if (! ftFile || ftFile->GetOpenCommand(wxEmptyString).IsEmpty())\r
819                         {\r
820                                 // 種類が取得できないときはテキストとみなす。\r
821                                 ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(this->conf.ReadId(CONF_DEFAULT_EXT, (wxString) wxT("txt")));\r
822                         }\r
823 \r
824                         // コマンドを実行。\r
825                         wxString szTempFile = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[0], wxPATH_DOS).GetFullName();\r
826                         bool fSuccess = tpi.nErrorCode == TPI_ERROR_SUCCESS && ftFile != NULL;\r
827                         myProcess * pCallback = new myProcess(szTempFile, swInfo.fnDestinationDirectory.GetPath());\r
828                         if (fSuccess)\r
829                         {\r
830 #ifdef __LINUX__\r
831                                 // Linuxでは引用符で囲む必要がある。\r
832                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(QuoteString(szTempFile)), wxEXEC_ASYNC, pCallback) > 0;\r
833 #else\r
834                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(szTempFile), wxEXEC_ASYNC, pCallback) > 0;\r
835 #endif\r
836                         }\r
837                         if (! fSuccess)\r
838                         {\r
839                                 pCallback->OnTerminate(0, 0);\r
840                         }\r
841                 }\r
842                 else\r
843                 {\r
844                         // 展開対象を決定。\r
845                         wxArrayString asFiles;\r
846                         myFileDataObject * objFile = new myFileDataObject();\r
847                         objFile->szTempDir = nMode == 3 ? swInfo.fnDestinationDirectory.GetPath() : swInfo.fnDestinationDirectory.GetFullPath();\r
848                         for (size_t i = 0; i < mkDlg.files.GetCount(); i++)\r
849                         {\r
850                                 wxString szFileName = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[i], wxPATH_DOS).GetFullName();\r
851                                 if (nMode == 3)\r
852                                 {\r
853                                         asFiles.Add(szFileName);\r
854                                 }\r
855                                 else\r
856                                 {\r
857                                         // リストに追加。\r
858                                         objFile->AddFile(szFileName);\r
859                                 }\r
860                         }\r
861                         if (nMode == 3)\r
862                         {\r
863                                 objFile->AddFile(objFile->szTempDir);\r
864                         }\r
865 \r
866                         if (nMode == 4)\r
867                         {\r
868                                 wxTheClipboard->SetData(objFile);\r
869                         }\r
870                         else\r
871                         {\r
872                                 // 自身にドロップされると煩雑なので、一時的にドロップを受け付けないようにしておく。\r
873                                 this->SetDropTarget(NULL);\r
874 \r
875                                 // DnD開始。\r
876                                 wxDropSource dropSource(* objFile, this);\r
877                                 wxDragResult drResult = dropSource.DoDragDrop();\r
878                                 if (drResult != wxDragCancel && drResult != wxDragNone && drResult != wxDragMove)\r
879                                 {\r
880 #ifdef __LINUX__\r
881                                         // Linuxではまだ処理が終わっていない(コンテキストメニューが表示されている)ので、とりあえず3秒だけ待つ。\r
882                                         sleep(3);\r
883 #endif\r
884                                 }\r
885                                 this->SetDropTarget(new myFileDropTarget(this));\r
886 \r
887                                 // ディレクトリDnDのときは、先にディレクトリの中のファイルを消しておく。\r
888                                 if (nMode == 3)\r
889                                 {\r
890                                         for (size_t i = 0; i < asFiles.GetCount(); i++)\r
891                                         {\r
892                                                 chmod(asFiles[i].ToUTF8(), 0600);\r
893                                                 ::wxRemoveFile(asFiles[i]);\r
894                                         }\r
895                                 }\r
896 \r
897                                 delete objFile;\r
898                         }\r
899                 }\r
900         }\r
901 }\r
902 \r
903 void MainFrame::OnArcDelete(wxCommandEvent& e)\r
904 {\r
905         // 全ファイル削除は危険ではないかと。\r
906         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
907         {\r
908                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
909                 SetMenuToolState("Arc_Delete", false);\r
910                 return;\r
911         }\r
912 \r
913         if (::AskDlg(_("Are you sure to delete selected files?"), this) == wxNO)\r
914         {\r
915                 return;\r
916         }\r
917 \r
918         // 処理を行う。\r
919         {\r
920                 wxArrayString asFiles = MakeTargetFileList(this);\r
921                 ProcessDialog procDlg;\r
922                 procDlg.fnArchive  = & this->fnArchive;\r
923                 procDlg.nFileCount = asFiles.GetCount();\r
924                 procDlg.Show(true);\r
925 \r
926                 TPI_SWITCHES swInfo;\r
927                 tpi.Command(TPI_COMMAND_DELETE, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
928                 this->ErrorCheck(tpi.nErrorCode);\r
929                 procDlg.Show(false);\r
930         }\r
931 \r
932         // 書庫を再読み込みする。\r
933         this->OnArcOpen(e);\r
934 }\r
935 \r
936 void MainFrame::OnArcTest(wxCommandEvent&)\r
937 {\r
938         // 処理を行う。\r
939         wxArrayString asFiles = MakeTargetFileList(this);\r
940         ProcessDialog procDlg;\r
941         procDlg.fnArchive  = & this->fnArchive;\r
942         procDlg.nFileCount = asFiles.GetCount();\r
943         procDlg.Show(true);\r
944 \r
945         TPI_SWITCHES swInfo;\r
946         bool bIsCorrect = tpi.Command(TPI_COMMAND_TEST, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
947         procDlg.Show(false);\r
948 \r
949         if (bIsCorrect)\r
950         {\r
951                 wxLogMessage(_("This is a correct archive."));\r
952         }\r
953         else\r
954         {\r
955                 this->ErrorCheck(tpi.nErrorCode);\r
956         }\r
957 }\r
958 \r
959 void MainFrame::OnArcRepair(wxCommandEvent&)\r
960 {\r
961         // 処理を行う。\r
962         wxArrayString asFiles = MakeTargetFileList(this);\r
963         ProcessDialog procDlg;\r
964         procDlg.fnArchive  = & this->fnArchive;\r
965         procDlg.nFileCount = asFiles.GetCount();\r
966         procDlg.Show(true);\r
967 \r
968         TPI_SWITCHES swInfo;\r
969         tpi.Command(TPI_COMMAND_REPAIR, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
970         this->ErrorCheck(tpi.nErrorCode);\r
971         procDlg.Show(false);    \r
972 }\r
973 \r
974 void MainFrame::OnExeCopy(wxCommandEvent & e)\r
975 {\r
976         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
977         {\r
978                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
979                 this->menubar->Enable(XRCID("Exe_Copy"), false);\r
980                 return;\r
981         }\r
982 \r
983         if (! wxTheClipboard->Open())\r
984         {\r
985                 return;\r
986         }\r
987 \r
988         e.SetInt(4);\r
989         this->OnArcExtract(e);\r
990         wxTheClipboard->Close();\r
991 }\r
992 \r
993 void MainFrame::OnViewMode(wxCommandEvent & e)\r
994 {\r
995         int n = e.GetId();\r
996         this->menubar->Check(n, true);\r
997         this->list_ctrl->SetSingleStyle(wxLC_REPORT, n == XRCID("Exe_View_Details"));\r
998         this->list_ctrl->SetSingleStyle(wxLC_ICON,   n == XRCID("Exe_View_Icons"));\r
999         this->list_ctrl->SetSingleStyle(wxLC_LIST,   n == XRCID("Exe_View_List"));\r
1000 }\r
1001 \r
1002 void MainFrame::OnShowToolBar(wxCommandEvent & e)\r
1003 {\r
1004         this->toolbar->Show(e.IsChecked());\r
1005 }\r
1006 \r
1007 void MainFrame::OnShowStatusBar(wxCommandEvent & e)\r
1008 {\r
1009         this->statusbar->Show(e.IsChecked());\r
1010 }\r
1011 \r
1012 void MainFrame::OnSelectAll(wxCommandEvent &)\r
1013 {\r
1014         for (int i = 0; i < this->list_ctrl->GetItemCount(); i++)\r
1015         {\r
1016                 this->list_ctrl->Select(i, true);\r
1017         }\r
1018 }\r
1019 \r
1020 // TreeView\r
1021 \r
1022 void MainFrame::OnTreeChanged(wxTreeEvent& e)\r
1023 {\r
1024         // ツリービューからパスを取得。\r
1025         wxString szNodePath = TreeView_GetItemPath(this->tree_ctrl, e.GetItem());\r
1026         // リストビューを初期化。\r
1027         this->list_ctrl->apShowFile.Clear();\r
1028         this->list_ctrl->DeleteAllItems();\r
1029         g_hIconLL.RemoveAll();\r
1030         g_hIconLS.RemoveAll();\r
1031 \r
1032         // 現在のアイテムの選択状態を無効にしておく。\r
1033         long nSelected = this->list_ctrl->GetFirstSelected();\r
1034         while (nSelected != -1)\r
1035         {\r
1036                 this->list_ctrl->Select(nSelected, false);\r
1037                 nSelected = this->list_ctrl->GetNextSelected(nSelected);\r
1038         }\r
1039 \r
1040         // アイコン設定。\r
1041         this->list_ctrl->SetImageList(& g_hIconLL, wxIMAGE_LIST_NORMAL);\r
1042         this->list_ctrl->SetImageList(& g_hIconLS, wxIMAGE_LIST_SMALL);\r
1043 \r
1044         // 配列と比較し、パスが一致しなければ消す。\r
1045         for (size_t i = 0; i < this->fileinfo.GetCount(); i++)\r
1046         {\r
1047                 // パスを比較。\r
1048                 if (szNodePath == wxT("*") || szNodePath == this->fileinfo[i].fnFileName.GetPath())\r
1049                 {\r
1050                         // 項目がフォルダであるなら無視。\r
1051                         if (this->fileinfo[i].fnFileName.IsDir() || ! TreeView_CheckNewerItem(this->tree_ctrl, this->tree_ctrl->GetLastChild(this->tree_ctrl->GetRootItem()), this->fileinfo[i].fnFileName.GetFullPath(), false))\r
1052                         {\r
1053                                 continue;\r
1054                         }\r
1055 \r
1056                         // フィルタにかからなければ無視。\r
1057                         if (this->fileinfo[i].fnFileName.GetFullName().MakeLower().Find(this->tcFilter->GetValue().MakeLower()) == wxNOT_FOUND)\r
1058                         {\r
1059                                 continue;\r
1060                         }\r
1061 \r
1062                         this->list_ctrl->apShowFile.Add(& this->fileinfo[i]);\r
1063                 }\r
1064         }\r
1065 \r
1066         // ソートして表示。\r
1067         this->list_ctrl->apShowFile.Sort(& ListCtrlCompareProc);\r
1068         this->list_ctrl->SetItemCount(this->list_ctrl->apShowFile.GetCount());\r
1069 }\r
1070 \r
1071 void MainFrame::OnTreeBeginDrag(wxTreeEvent& e)\r
1072 {\r
1073         // TODO : アイテムが子階層を持っていても展開できない。\r
1074         this->tree_ctrl->SelectItem(e.GetItem());\r
1075 \r
1076         wxCommandEvent e1;\r
1077         e1.SetInt(3);\r
1078         this->OnArcExtract(e1);\r
1079 }\r
1080 \r
1081 void MainFrame::OnContextMenu(wxContextMenuEvent& e)\r
1082 {\r
1083         wxPoint p = e.GetPosition();\r
1084         this->list_ctrl->PopupMenu(this->menubar->GetMenu(1), p == wxDefaultPosition ? this->list_ctrl->GetPosition() : this->list_ctrl->ScreenToClient(p));\r
1085 }\r
1086 \r
1087 // ListView\r
1088 \r
1089 void MainFrame::OnListItemSelect(wxListEvent&)\r
1090 {\r
1091         // ファイルに対する動作の設定。但し、選択解除時はwxのバグで呼び出されない。\r
1092         bool fEnable = this->list_ctrl->GetSelectedItemCount() > 0;\r
1093         SetMenuToolState("Arc_Delete", fEnable && (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_DELETE) == TPI_COMMAND_DELETE && this->aiArchive.fiInfo.fArchive);\r
1094         this->menubar->Enable(XRCID("Exe_Copy"), fEnable);\r
1095 }\r
1096 \r
1097 void MainFrame::OnListItemDClick(wxListEvent&)\r
1098 {\r
1099         wxCommandEvent e;\r
1100         e.SetInt(1);\r
1101         this->OnArcExtract(e);\r
1102 }\r
1103 \r
1104 void MainFrame::OnListBeginDrag(wxListEvent&)\r
1105 {\r
1106         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
1107         {\r
1108                 // アイテムを選択せずドラッグしようとした場合。\r
1109                 return;\r
1110         }\r
1111 \r
1112         wxCommandEvent e;\r
1113         e.SetInt(2);\r
1114         this->OnArcExtract(e);\r
1115 }\r
1116 \r
1117 // Filter\r
1118 \r
1119 void MainFrame::OnFilter(wxCommandEvent&)\r
1120 {\r
1121         wxTreeEvent e;\r
1122         e.SetItem(this->tree_ctrl->GetSelection());\r
1123         this->OnTreeChanged(e);\r
1124 }\r
1125 \r
1126 // イベントハンドラ以外。\r
1127 \r
1128 bool MainFrame::LoadTPI(const wxString & szFileName, wxULongLong_t * llFileCount)\r
1129 {\r
1130         // 書庫を開いていれば閉じておく。\r
1131         wxCommandEvent e;\r
1132         this->OnArcClose(e);\r
1133 \r
1134         // TPIを読み込み。\r
1135         wxDir fs(L_DIR_B_LIB);\r
1136         wxString szTPIName;\r
1137         if (fs.GetFirst(& szTPIName, wxT("*" TPI_EXT)))\r
1138         {\r
1139                 do\r
1140                 {\r
1141                         // 初期化。\r
1142                         if (! tpi.InitLibrary(L_DIR_B_LIB + szTPIName, szFileName, TPICallbackProc))\r
1143                         {\r
1144                                 tpi.FreeLibrary();\r
1145                                 continue;\r
1146                         }\r
1147 \r
1148                         // 対応確認。\r
1149                         if (! tpi.OpenArchive(szFileName, llFileCount))\r
1150                         {\r
1151                                 tpi.FreeLibrary();\r
1152                                 * llFileCount = 0;\r
1153                                 continue;\r
1154                         }\r
1155                         return true;\r
1156                 }\r
1157                 while (fs.GetNext(& szTPIName));\r
1158         }\r
1159         return false;\r
1160 }\r
1161 \r
1162 int MainFrame::ErrorCheck(int nErrorCode, const wxString & szAPIName)\r
1163 {\r
1164         switch (nErrorCode)\r
1165         {\r
1166         case TPI_ERROR_SUCCESS:\r
1167         case TPI_ERROR_S_ENDOFDATA:\r
1168         case TPI_CALLBACK_CONTINUE:\r
1169                 break;\r
1170         case TPI_ERROR_D_UNSUPPORTED:\r
1171                 wxLogError(_("Sorry, this function is not supported yet."));\r
1172                 break;\r
1173         case TPI_ERROR_D_SKIPPED:\r
1174         case TPI_CALLBACK_CANCEL:\r
1175                 wxLogError(_("This operation is canceled by the user."));\r
1176                 break;\r
1177         default:\r
1178                 wxLogError(_("Error: %s()!\nError code: %d"), szAPIName.c_str(), nErrorCode);\r
1179         }\r
1180         return nErrorCode;\r
1181 }\r